@adminforth/agent 1.47.2 → 1.48.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/middleware/apiBasedTools.ts +6 -1
- package/agent/simpleAgent.ts +7 -1
- package/agent/skills/registry.ts +41 -37
- package/agent/systemPrompt.ts +10 -11
- package/agent/tools/fetchSkill.ts +13 -3
- package/agent/tools/index.ts +2 -1
- package/agentTurnService.ts +1 -0
- package/build.log +2 -2
- package/custom/composables/agentStore/useAgentSessions.ts +6 -3
- package/custom/conversation_area/TextRenderer.vue +5 -1
- package/dist/agent/middleware/apiBasedTools.js +3 -1
- package/dist/agent/simpleAgent.d.ts +1 -0
- package/dist/agent/simpleAgent.js +2 -2
- package/dist/agent/skills/registry.d.ts +4 -6
- package/dist/agent/skills/registry.js +21 -36
- package/dist/agent/systemPrompt.js +8 -11
- package/dist/agent/tools/fetchSkill.d.ts +1 -1
- package/dist/agent/tools/fetchSkill.js +4 -4
- package/dist/agent/tools/index.d.ts +1 -1
- package/dist/agent/tools/index.js +3 -3
- package/dist/agentTurnService.js +1 -0
- package/dist/custom/composables/agentStore/useAgentSessions.ts +6 -3
- package/dist/custom/conversation_area/TextRenderer.vue +5 -1
- package/package.json +1 -1
|
@@ -66,10 +66,15 @@ export function createApiBasedToolsMiddleware(
|
|
|
66
66
|
const tools = [...enabledApiToolNames]
|
|
67
67
|
.filter((toolName) => !alwaysAvailableApiToolNames.has(toolName))
|
|
68
68
|
.map((toolName) => dynamicTools[toolName]);
|
|
69
|
+
const availableTools = [...request.tools, ...tools];
|
|
70
|
+
|
|
71
|
+
logger.info(
|
|
72
|
+
`AdminForth Agent callable tools: ${availableTools.map((tool) => tool.name).join(", ")}`,
|
|
73
|
+
);
|
|
69
74
|
|
|
70
75
|
return handler({
|
|
71
76
|
...request,
|
|
72
|
-
tools:
|
|
77
|
+
tools: availableTools,
|
|
73
78
|
});
|
|
74
79
|
},
|
|
75
80
|
async wrapToolCall(request, handler) {
|
package/agent/simpleAgent.ts
CHANGED
|
@@ -230,6 +230,7 @@ export async function callAgent(params: {
|
|
|
230
230
|
adminforth: IAdminForth;
|
|
231
231
|
apiBasedTools: Record<string, ApiBasedTool>;
|
|
232
232
|
customComponentsDir: string;
|
|
233
|
+
pluginCustomFolderPaths: string[];
|
|
233
234
|
sessionId: string;
|
|
234
235
|
turnId: string;
|
|
235
236
|
currentPage?: CurrentPageContext;
|
|
@@ -249,6 +250,7 @@ export async function callAgent(params: {
|
|
|
249
250
|
adminforth,
|
|
250
251
|
apiBasedTools,
|
|
251
252
|
customComponentsDir,
|
|
253
|
+
pluginCustomFolderPaths,
|
|
252
254
|
sessionId,
|
|
253
255
|
turnId,
|
|
254
256
|
currentPage,
|
|
@@ -258,7 +260,11 @@ export async function callAgent(params: {
|
|
|
258
260
|
sequenceDebugSink,
|
|
259
261
|
} = params;
|
|
260
262
|
|
|
261
|
-
const tools = await createAgentTools(
|
|
263
|
+
const tools = await createAgentTools(
|
|
264
|
+
customComponentsDir,
|
|
265
|
+
apiBasedTools,
|
|
266
|
+
pluginCustomFolderPaths,
|
|
267
|
+
);
|
|
262
268
|
const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
|
|
263
269
|
const sequenceDebugMiddleware = createSequenceDebugMiddleware(
|
|
264
270
|
sequenceDebugSink,
|
package/agent/skills/registry.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
3
|
import { parse as parseYaml } from "yaml";
|
|
5
4
|
|
|
6
|
-
const PLUGIN_SKILLS_DIRECTORY_PATH = fileURLToPath(
|
|
7
|
-
new URL("../../custom/skills/", import.meta.url),
|
|
8
|
-
);
|
|
9
|
-
const USER_PLUGIN_SKILLS_DIRECTORY_PATH_SEGMENTS = [
|
|
10
|
-
"plugins",
|
|
11
|
-
"adminforth-agent",
|
|
12
|
-
"skills",
|
|
13
|
-
];
|
|
14
5
|
const SKILL_MARKDOWN_FILENAME = "SKILL.md";
|
|
15
6
|
const SKILL_FRONTMATTER_SEPARATOR = "\n---\n";
|
|
16
7
|
|
|
@@ -21,6 +12,13 @@ export interface AgentSkillManifest {
|
|
|
21
12
|
instructions: string;
|
|
22
13
|
}
|
|
23
14
|
|
|
15
|
+
function normalizePluginSkillDirectoryPaths(pluginCustomFolderPaths: string[] = []) {
|
|
16
|
+
return Array.from(new Set(
|
|
17
|
+
pluginCustomFolderPaths
|
|
18
|
+
.map((pluginCustomFolderPath) => path.resolve(pluginCustomFolderPath, "skills")),
|
|
19
|
+
));
|
|
20
|
+
}
|
|
21
|
+
|
|
24
22
|
function parseSkillManifest(directoryName: string, markdown: string): AgentSkillManifest {
|
|
25
23
|
const [frontmatterBlock, instructions = ""] = markdown.split("\r\n").join("\n").split(
|
|
26
24
|
SKILL_FRONTMATTER_SEPARATOR,
|
|
@@ -83,43 +81,42 @@ export function getProjectSkillsDirectoryPath(customComponentsDir: string) {
|
|
|
83
81
|
return path.resolve(customComponentsDir, "skills");
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function getProjectSkillDirectoryPaths(customComponentsDir: string) {
|
|
94
|
-
return [
|
|
84
|
+
function getProjectSkillDirectoryPaths(
|
|
85
|
+
customComponentsDir: string,
|
|
86
|
+
pluginCustomFolderPaths: string[] = [],
|
|
87
|
+
) {
|
|
88
|
+
return Array.from(new Set([
|
|
95
89
|
getProjectSkillsDirectoryPath(customComponentsDir),
|
|
96
|
-
|
|
97
|
-
];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export async function listBundledSkillManifests() {
|
|
101
|
-
return await listDirectorySkillManifests(PLUGIN_SKILLS_DIRECTORY_PATH);
|
|
90
|
+
...normalizePluginSkillDirectoryPaths(pluginCustomFolderPaths),
|
|
91
|
+
]));
|
|
102
92
|
}
|
|
103
93
|
|
|
104
|
-
export async function listProjectSkillManifests(
|
|
94
|
+
export async function listProjectSkillManifests(
|
|
95
|
+
customComponentsDir: string,
|
|
96
|
+
pluginCustomFolderPaths: string[] = [],
|
|
97
|
+
) {
|
|
105
98
|
return mergeSkillManifests(
|
|
106
99
|
await Promise.all(
|
|
107
|
-
getProjectSkillDirectoryPaths(customComponentsDir).map(
|
|
100
|
+
getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths).map(
|
|
108
101
|
listDirectorySkillManifests,
|
|
109
102
|
),
|
|
110
103
|
),
|
|
111
104
|
);
|
|
112
105
|
}
|
|
113
106
|
|
|
114
|
-
export async function listSkillManifests(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
export async function listSkillManifests(
|
|
108
|
+
customComponentsDir: string,
|
|
109
|
+
pluginCustomFolderPaths: string[] = [],
|
|
110
|
+
) {
|
|
111
|
+
return await listProjectSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
119
112
|
}
|
|
120
113
|
|
|
121
|
-
export async function loadSkillManifest(
|
|
122
|
-
|
|
114
|
+
export async function loadSkillManifest(
|
|
115
|
+
skillName: string,
|
|
116
|
+
customComponentsDir: string,
|
|
117
|
+
pluginCustomFolderPaths: string[] = [],
|
|
118
|
+
) {
|
|
119
|
+
const manifests = await listSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
123
120
|
|
|
124
121
|
return (
|
|
125
122
|
manifests.find(
|
|
@@ -129,16 +126,23 @@ export async function loadSkillManifest(skillName: string, customComponentsDir:
|
|
|
129
126
|
);
|
|
130
127
|
}
|
|
131
128
|
|
|
132
|
-
export async function loadSkillMarkdown(
|
|
133
|
-
|
|
129
|
+
export async function loadSkillMarkdown(
|
|
130
|
+
skillName: string,
|
|
131
|
+
customComponentsDir: string,
|
|
132
|
+
pluginCustomFolderPaths: string[] = [],
|
|
133
|
+
) {
|
|
134
|
+
const manifest = await loadSkillManifest(
|
|
135
|
+
skillName,
|
|
136
|
+
customComponentsDir,
|
|
137
|
+
pluginCustomFolderPaths,
|
|
138
|
+
);
|
|
134
139
|
|
|
135
140
|
if (!manifest) {
|
|
136
141
|
return null;
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
const directories = [
|
|
140
|
-
...getProjectSkillDirectoryPaths(customComponentsDir),
|
|
141
|
-
PLUGIN_SKILLS_DIRECTORY_PATH,
|
|
145
|
+
...getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths),
|
|
142
146
|
];
|
|
143
147
|
|
|
144
148
|
for (const skillsDirectoryPath of directories) {
|
package/agent/systemPrompt.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AdminForthResource, AdminUser, IAdminForth } from "adminforth";
|
|
2
2
|
import type { DetectedLanguage } from "./languageDetect.js";
|
|
3
3
|
import {
|
|
4
|
-
listBundledSkillManifests,
|
|
5
4
|
listProjectSkillManifests,
|
|
6
5
|
type AgentSkillManifest,
|
|
7
6
|
} from "./skills/registry.js";
|
|
@@ -96,10 +95,12 @@ export async function buildAgentSystemPrompt(
|
|
|
96
95
|
hiddenResourceIds: Iterable<string> = [],
|
|
97
96
|
) {
|
|
98
97
|
const customComponentsDir = adminforth.config.customization.customComponentsDir ?? "custom";
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
const pluginCustomFolderPaths = adminforth.activatedPlugins
|
|
99
|
+
.map((plugin) => plugin.customFolderPath);
|
|
100
|
+
const skills = await listProjectSkillManifests(
|
|
101
|
+
customComponentsDir,
|
|
102
|
+
pluginCustomFolderPaths,
|
|
103
|
+
);
|
|
103
104
|
const adminBasePath = adminforth.config.baseUrlSlashed;
|
|
104
105
|
const hiddenResourceIdSet = new Set(hiddenResourceIds);
|
|
105
106
|
const visibleResources = adminforth.config.resources.filter(
|
|
@@ -109,11 +110,9 @@ export async function buildAgentSystemPrompt(
|
|
|
109
110
|
DEFAULT_AGENT_SYSTEM_PROMPT,
|
|
110
111
|
`ADMIN_BASE_PATH: ${adminBasePath}`,
|
|
111
112
|
`List of resources:\n${formatResources(visibleResources)}`,
|
|
112
|
-
|
|
113
|
-
? `You have
|
|
113
|
+
skills.length > 0
|
|
114
|
+
? `You have skills set:\n${formatSkills(skills, "skill_name")}`
|
|
114
115
|
: "",
|
|
115
|
-
"You have next default skills which you can fallback to if primary skill set does not provide a good skill:\n" +
|
|
116
|
-
formatSkills(defaultSkills, "skill_name"),
|
|
117
116
|
"Before using any skill, call fetch_skill to load its full instructions.",
|
|
118
117
|
"The fetched skill response starts with 'Tools mentioned in this skill'. Read that list first.",
|
|
119
118
|
"You can use get_resource immediately to inspect resource structure and column names.",
|
|
@@ -123,8 +122,8 @@ export async function buildAgentSystemPrompt(
|
|
|
123
122
|
"If a fetched skill lists a non-base tool you need, call fetch_tool_schema for it immediately instead of telling the user the tool is unavailable.",
|
|
124
123
|
"For example: for record creation load mutate_data, read its tool list, call fetch_tool_schema for create_record, and then use create_record after confirmation.",
|
|
125
124
|
"When fetch_tool_schema succeeds, that tool becomes available on the next step.",
|
|
126
|
-
"All admin links must be relative
|
|
127
|
-
"Build record links as
|
|
125
|
+
"All admin links must be root-relative and start with '/'.",
|
|
126
|
+
"Build record links as '/resource/{resourceId}/show/{primary key}'. Never use bare 'resource/{resourceId}/show/{primary key}' without the leading slash.",
|
|
128
127
|
"Try to call as many tools as possible in parallel in one step.",
|
|
129
128
|
];
|
|
130
129
|
|
|
@@ -21,14 +21,24 @@ function serializeSkillManifests(skillManifests: AgentSkillManifest[]) {
|
|
|
21
21
|
}));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export async function createFetchSkillTool(
|
|
25
|
-
|
|
24
|
+
export async function createFetchSkillTool(
|
|
25
|
+
customComponentsDir: string,
|
|
26
|
+
pluginCustomFolderPaths: string[] = [],
|
|
27
|
+
) {
|
|
28
|
+
const availableSkills = await listSkillManifests(
|
|
29
|
+
customComponentsDir,
|
|
30
|
+
pluginCustomFolderPaths,
|
|
31
|
+
);
|
|
26
32
|
const availableSkillNames = availableSkills.map((skill) => skill.name);
|
|
27
33
|
|
|
28
34
|
return tool(
|
|
29
35
|
async ({ skillName }) => {
|
|
30
36
|
try {
|
|
31
|
-
const skillMarkdown = await loadSkillMarkdown(
|
|
37
|
+
const skillMarkdown = await loadSkillMarkdown(
|
|
38
|
+
skillName,
|
|
39
|
+
customComponentsDir,
|
|
40
|
+
pluginCustomFolderPaths,
|
|
41
|
+
);
|
|
32
42
|
|
|
33
43
|
if (!skillMarkdown) {
|
|
34
44
|
return [
|
package/agent/tools/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export const ALWAYS_AVAILABLE_API_TOOL_NAMES = ["get_resource"] as const;
|
|
|
10
10
|
export async function createAgentTools(
|
|
11
11
|
customComponentsDir: string,
|
|
12
12
|
apiBasedTools: Record<string, ApiBasedTool>,
|
|
13
|
+
pluginCustomFolderPaths: string[] = [],
|
|
13
14
|
): Promise<ClientTool[]> {
|
|
14
15
|
return [
|
|
15
16
|
...ALWAYS_AVAILABLE_API_TOOL_NAMES.map((toolName) => {
|
|
@@ -22,7 +23,7 @@ export async function createAgentTools(
|
|
|
22
23
|
return createApiTool(toolName, apiBasedTool);
|
|
23
24
|
}),
|
|
24
25
|
createGetUserLocationTool(),
|
|
25
|
-
await createFetchSkillTool(customComponentsDir),
|
|
26
|
+
await createFetchSkillTool(customComponentsDir, pluginCustomFolderPaths),
|
|
26
27
|
await createFetchToolSchemaTool(apiBasedTools),
|
|
27
28
|
];
|
|
28
29
|
}
|
package/agentTurnService.ts
CHANGED
|
@@ -138,6 +138,7 @@ export class AgentTurnService {
|
|
|
138
138
|
adminforth,
|
|
139
139
|
apiBasedTools,
|
|
140
140
|
customComponentsDir: adminforth.config.customization.customComponentsDir ?? "custom",
|
|
141
|
+
pluginCustomFolderPaths: adminforth.activatedPlugins.map((plugin) => plugin.customFolderPath),
|
|
141
142
|
sessionId: input.sessionId,
|
|
142
143
|
turnId: input.turnId,
|
|
143
144
|
currentPage: input.currentPage,
|
package/build.log
CHANGED
|
@@ -62,5 +62,5 @@ custom/speech_recognition_frontend/voiceActivityDetection.ts
|
|
|
62
62
|
custom/speech_recognition_frontend/types/
|
|
63
63
|
custom/speech_recognition_frontend/types/voice-activity-detection.d.ts
|
|
64
64
|
|
|
65
|
-
sent 1,667,
|
|
66
|
-
total size is 1,663,
|
|
65
|
+
sent 1,667,891 bytes received 921 bytes 3,337,624.00 bytes/sec
|
|
66
|
+
total size is 1,663,796 speedup is 1.00
|
|
@@ -3,7 +3,7 @@ import { callAdminForthApi } from '@/utils';
|
|
|
3
3
|
import type { Chat } from '../../chat';
|
|
4
4
|
import type { IAgentSession, ISessionsListItem, IPart } from '../../types';
|
|
5
5
|
import { PRE_SESSION_ID } from './constants';
|
|
6
|
-
import {
|
|
6
|
+
import { i18nInstance } from '@/i18n';
|
|
7
7
|
|
|
8
8
|
type AdminforthLike = {
|
|
9
9
|
confirm(options: { message: string; yes: string; no: string }): Promise<boolean>;
|
|
@@ -42,7 +42,10 @@ export function createAgentSessionManager({
|
|
|
42
42
|
return [...sessionsListToSort].sort((a: ISessionsListItem, b: ISessionsListItem) => b.timestamp.localeCompare(a.timestamp));
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
function t(key: string) {
|
|
46
|
+
return i18nInstance?.global.t(key) ?? key;
|
|
47
|
+
}
|
|
48
|
+
|
|
46
49
|
function saveCurrentSessionInCache() {
|
|
47
50
|
if (currentSession.value) {
|
|
48
51
|
currentSession.value.messages = currentChat.value?.messages.map((m: any) => ({
|
|
@@ -342,4 +345,4 @@ export function createAgentSessionManager({
|
|
|
342
345
|
setCurrentChatStatus,
|
|
343
346
|
updateLastAgentMessage
|
|
344
347
|
};
|
|
345
|
-
}
|
|
348
|
+
}
|
|
@@ -115,7 +115,11 @@
|
|
|
115
115
|
return `${window.location.pathname}${window.location.search}${href}`;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
const
|
|
118
|
+
const isAbsoluteWithScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href);
|
|
119
|
+
const baseUrl = isAbsoluteWithScheme
|
|
120
|
+
? undefined
|
|
121
|
+
: `${window.location.origin}/`;
|
|
122
|
+
const resolvedUrl = new URL(href, baseUrl ?? window.location.href);
|
|
119
123
|
if (resolvedUrl.origin !== window.location.origin) {
|
|
120
124
|
return null;
|
|
121
125
|
}
|
|
@@ -55,7 +55,9 @@ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
|
|
|
55
55
|
const tools = [...enabledApiToolNames]
|
|
56
56
|
.filter((toolName) => !alwaysAvailableApiToolNames.has(toolName))
|
|
57
57
|
.map((toolName) => dynamicTools[toolName]);
|
|
58
|
-
|
|
58
|
+
const availableTools = [...request.tools, ...tools];
|
|
59
|
+
logger.info(`AdminForth Agent callable tools: ${availableTools.map((tool) => tool.name).join(", ")}`);
|
|
60
|
+
return handler(Object.assign(Object.assign({}, request), { tools: availableTools }));
|
|
59
61
|
});
|
|
60
62
|
},
|
|
61
63
|
wrapToolCall(request, handler) {
|
|
@@ -50,6 +50,7 @@ export declare function callAgent(params: {
|
|
|
50
50
|
adminforth: IAdminForth;
|
|
51
51
|
apiBasedTools: Record<string, ApiBasedTool>;
|
|
52
52
|
customComponentsDir: string;
|
|
53
|
+
pluginCustomFolderPaths: string[];
|
|
53
54
|
sessionId: string;
|
|
54
55
|
turnId: string;
|
|
55
56
|
currentPage?: CurrentPageContext;
|
|
@@ -132,8 +132,8 @@ export function createAgentChatModel(params) {
|
|
|
132
132
|
}
|
|
133
133
|
export function callAgent(params) {
|
|
134
134
|
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
-
const { name, model, summaryModel, modelMiddleware = [], checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, sessionId, turnId, currentPage, userTimeZone, abortSignal, emitToolCallEvent, sequenceDebugSink, } = params;
|
|
136
|
-
const tools = yield createAgentTools(customComponentsDir, apiBasedTools);
|
|
135
|
+
const { name, model, summaryModel, modelMiddleware = [], checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, pluginCustomFolderPaths, sessionId, turnId, currentPage, userTimeZone, abortSignal, emitToolCallEvent, sequenceDebugSink, } = params;
|
|
136
|
+
const tools = yield createAgentTools(customComponentsDir, apiBasedTools, pluginCustomFolderPaths);
|
|
137
137
|
const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
|
|
138
138
|
const sequenceDebugMiddleware = createSequenceDebugMiddleware(sequenceDebugSink);
|
|
139
139
|
const middleware = [
|
|
@@ -5,9 +5,7 @@ export interface AgentSkillManifest {
|
|
|
5
5
|
instructions: string;
|
|
6
6
|
}
|
|
7
7
|
export declare function getProjectSkillsDirectoryPath(customComponentsDir: string): string;
|
|
8
|
-
export declare function
|
|
9
|
-
export declare function
|
|
10
|
-
export declare function
|
|
11
|
-
export declare function
|
|
12
|
-
export declare function loadSkillManifest(skillName: string, customComponentsDir: string): Promise<AgentSkillManifest | null>;
|
|
13
|
-
export declare function loadSkillMarkdown(skillName: string, customComponentsDir: string): Promise<string | null>;
|
|
8
|
+
export declare function listProjectSkillManifests(customComponentsDir: string, pluginCustomFolderPaths?: string[]): Promise<AgentSkillManifest[]>;
|
|
9
|
+
export declare function listSkillManifests(customComponentsDir: string, pluginCustomFolderPaths?: string[]): Promise<AgentSkillManifest[]>;
|
|
10
|
+
export declare function loadSkillManifest(skillName: string, customComponentsDir: string, pluginCustomFolderPaths?: string[]): Promise<AgentSkillManifest | null>;
|
|
11
|
+
export declare function loadSkillMarkdown(skillName: string, customComponentsDir: string, pluginCustomFolderPaths?: string[]): Promise<string | null>;
|
|
@@ -9,16 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { readdir, readFile } from "fs/promises";
|
|
11
11
|
import path from "path";
|
|
12
|
-
import { fileURLToPath } from "url";
|
|
13
12
|
import { parse as parseYaml } from "yaml";
|
|
14
|
-
const PLUGIN_SKILLS_DIRECTORY_PATH = fileURLToPath(new URL("../../custom/skills/", import.meta.url));
|
|
15
|
-
const USER_PLUGIN_SKILLS_DIRECTORY_PATH_SEGMENTS = [
|
|
16
|
-
"plugins",
|
|
17
|
-
"adminforth-agent",
|
|
18
|
-
"skills",
|
|
19
|
-
];
|
|
20
13
|
const SKILL_MARKDOWN_FILENAME = "SKILL.md";
|
|
21
14
|
const SKILL_FRONTMATTER_SEPARATOR = "\n---\n";
|
|
15
|
+
function normalizePluginSkillDirectoryPaths(pluginCustomFolderPaths = []) {
|
|
16
|
+
return Array.from(new Set(pluginCustomFolderPaths
|
|
17
|
+
.map((pluginCustomFolderPath) => path.resolve(pluginCustomFolderPath, "skills"))));
|
|
18
|
+
}
|
|
22
19
|
function parseSkillManifest(directoryName, markdown) {
|
|
23
20
|
var _a, _b;
|
|
24
21
|
const [frontmatterBlock, instructions = ""] = markdown.split("\r\n").join("\n").split(SKILL_FRONTMATTER_SEPARATOR, 2);
|
|
@@ -63,49 +60,37 @@ function mergeSkillManifests(skillGroups) {
|
|
|
63
60
|
export function getProjectSkillsDirectoryPath(customComponentsDir) {
|
|
64
61
|
return path.resolve(customComponentsDir, "skills");
|
|
65
62
|
}
|
|
66
|
-
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
function getProjectSkillDirectoryPaths(customComponentsDir) {
|
|
70
|
-
return [
|
|
63
|
+
function getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths = []) {
|
|
64
|
+
return Array.from(new Set([
|
|
71
65
|
getProjectSkillsDirectoryPath(customComponentsDir),
|
|
72
|
-
|
|
73
|
-
];
|
|
66
|
+
...normalizePluginSkillDirectoryPaths(pluginCustomFolderPaths),
|
|
67
|
+
]));
|
|
74
68
|
}
|
|
75
|
-
export function
|
|
76
|
-
return __awaiter(this,
|
|
77
|
-
return yield
|
|
69
|
+
export function listProjectSkillManifests(customComponentsDir_1) {
|
|
70
|
+
return __awaiter(this, arguments, void 0, function* (customComponentsDir, pluginCustomFolderPaths = []) {
|
|
71
|
+
return mergeSkillManifests(yield Promise.all(getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths).map(listDirectorySkillManifests)));
|
|
78
72
|
});
|
|
79
73
|
}
|
|
80
|
-
export function
|
|
81
|
-
return __awaiter(this,
|
|
82
|
-
return
|
|
74
|
+
export function listSkillManifests(customComponentsDir_1) {
|
|
75
|
+
return __awaiter(this, arguments, void 0, function* (customComponentsDir, pluginCustomFolderPaths = []) {
|
|
76
|
+
return yield listProjectSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
83
77
|
});
|
|
84
78
|
}
|
|
85
|
-
export function
|
|
86
|
-
return __awaiter(this,
|
|
87
|
-
return mergeSkillManifests([
|
|
88
|
-
yield listProjectSkillManifests(customComponentsDir),
|
|
89
|
-
yield listBundledSkillManifests(),
|
|
90
|
-
]);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
export function loadSkillManifest(skillName, customComponentsDir) {
|
|
94
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
export function loadSkillManifest(skillName_1, customComponentsDir_1) {
|
|
80
|
+
return __awaiter(this, arguments, void 0, function* (skillName, customComponentsDir, pluginCustomFolderPaths = []) {
|
|
95
81
|
var _a;
|
|
96
|
-
const manifests = yield listSkillManifests(customComponentsDir);
|
|
82
|
+
const manifests = yield listSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
97
83
|
return ((_a = manifests.find((manifest) => manifest.name === skillName || manifest.directoryName === skillName)) !== null && _a !== void 0 ? _a : null);
|
|
98
84
|
});
|
|
99
85
|
}
|
|
100
|
-
export function loadSkillMarkdown(
|
|
101
|
-
return __awaiter(this,
|
|
102
|
-
const manifest = yield loadSkillManifest(skillName, customComponentsDir);
|
|
86
|
+
export function loadSkillMarkdown(skillName_1, customComponentsDir_1) {
|
|
87
|
+
return __awaiter(this, arguments, void 0, function* (skillName, customComponentsDir, pluginCustomFolderPaths = []) {
|
|
88
|
+
const manifest = yield loadSkillManifest(skillName, customComponentsDir, pluginCustomFolderPaths);
|
|
103
89
|
if (!manifest) {
|
|
104
90
|
return null;
|
|
105
91
|
}
|
|
106
92
|
const directories = [
|
|
107
|
-
...getProjectSkillDirectoryPaths(customComponentsDir),
|
|
108
|
-
PLUGIN_SKILLS_DIRECTORY_PATH,
|
|
93
|
+
...getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths),
|
|
109
94
|
];
|
|
110
95
|
for (const skillsDirectoryPath of directories) {
|
|
111
96
|
try {
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { listProjectSkillManifests, } from "./skills/registry.js";
|
|
11
11
|
export const DEFAULT_AGENT_SYSTEM_PROMPT = [
|
|
12
12
|
"You are helpful AI Assistant for Admin Panel.",
|
|
13
13
|
// about admin
|
|
@@ -75,10 +75,9 @@ export function buildAgentSystemPrompt(adminforth_1) {
|
|
|
75
75
|
return __awaiter(this, arguments, void 0, function* (adminforth, hiddenResourceIds = []) {
|
|
76
76
|
var _a;
|
|
77
77
|
const customComponentsDir = (_a = adminforth.config.customization.customComponentsDir) !== null && _a !== void 0 ? _a : "custom";
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
]);
|
|
78
|
+
const pluginCustomFolderPaths = adminforth.activatedPlugins
|
|
79
|
+
.map((plugin) => plugin.customFolderPath);
|
|
80
|
+
const skills = yield listProjectSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
82
81
|
const adminBasePath = adminforth.config.baseUrlSlashed;
|
|
83
82
|
const hiddenResourceIdSet = new Set(hiddenResourceIds);
|
|
84
83
|
const visibleResources = adminforth.config.resources.filter((resource) => !hiddenResourceIdSet.has(resource.resourceId));
|
|
@@ -86,11 +85,9 @@ export function buildAgentSystemPrompt(adminforth_1) {
|
|
|
86
85
|
DEFAULT_AGENT_SYSTEM_PROMPT,
|
|
87
86
|
`ADMIN_BASE_PATH: ${adminBasePath}`,
|
|
88
87
|
`List of resources:\n${formatResources(visibleResources)}`,
|
|
89
|
-
|
|
90
|
-
? `You have
|
|
88
|
+
skills.length > 0
|
|
89
|
+
? `You have skills set:\n${formatSkills(skills, "skill_name")}`
|
|
91
90
|
: "",
|
|
92
|
-
"You have next default skills which you can fallback to if primary skill set does not provide a good skill:\n" +
|
|
93
|
-
formatSkills(defaultSkills, "skill_name"),
|
|
94
91
|
"Before using any skill, call fetch_skill to load its full instructions.",
|
|
95
92
|
"The fetched skill response starts with 'Tools mentioned in this skill'. Read that list first.",
|
|
96
93
|
"You can use get_resource immediately to inspect resource structure and column names.",
|
|
@@ -100,8 +97,8 @@ export function buildAgentSystemPrompt(adminforth_1) {
|
|
|
100
97
|
"If a fetched skill lists a non-base tool you need, call fetch_tool_schema for it immediately instead of telling the user the tool is unavailable.",
|
|
101
98
|
"For example: for record creation load mutate_data, read its tool list, call fetch_tool_schema for create_record, and then use create_record after confirmation.",
|
|
102
99
|
"When fetch_tool_schema succeeds, that tool becomes available on the next step.",
|
|
103
|
-
"All admin links must be relative
|
|
104
|
-
"Build record links as
|
|
100
|
+
"All admin links must be root-relative and start with '/'.",
|
|
101
|
+
"Build record links as '/resource/{resourceId}/show/{primary key}'. Never use bare 'resource/{resourceId}/show/{primary key}' without the leading slash.",
|
|
105
102
|
"Try to call as many tools as possible in parallel in one step.",
|
|
106
103
|
];
|
|
107
104
|
return sections.filter(Boolean).join("\n\n");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare function createFetchSkillTool(customComponentsDir: string): Promise<import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
2
|
+
export declare function createFetchSkillTool(customComponentsDir: string, pluginCustomFolderPaths?: string[]): Promise<import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
3
3
|
skillName: z.ZodString;
|
|
4
4
|
}, z.core.$strip>, {
|
|
5
5
|
skillName: string;
|
|
@@ -21,13 +21,13 @@ function serializeSkillManifests(skillManifests) {
|
|
|
21
21
|
description: skill.description,
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
|
-
export function createFetchSkillTool(
|
|
25
|
-
return __awaiter(this,
|
|
26
|
-
const availableSkills = yield listSkillManifests(customComponentsDir);
|
|
24
|
+
export function createFetchSkillTool(customComponentsDir_1) {
|
|
25
|
+
return __awaiter(this, arguments, void 0, function* (customComponentsDir, pluginCustomFolderPaths = []) {
|
|
26
|
+
const availableSkills = yield listSkillManifests(customComponentsDir, pluginCustomFolderPaths);
|
|
27
27
|
const availableSkillNames = availableSkills.map((skill) => skill.name);
|
|
28
28
|
return tool((_a) => __awaiter(this, [_a], void 0, function* ({ skillName }) {
|
|
29
29
|
try {
|
|
30
|
-
const skillMarkdown = yield loadSkillMarkdown(skillName, customComponentsDir);
|
|
30
|
+
const skillMarkdown = yield loadSkillMarkdown(skillName, customComponentsDir, pluginCustomFolderPaths);
|
|
31
31
|
if (!skillMarkdown) {
|
|
32
32
|
return [
|
|
33
33
|
`Skill "${skillName}" not found.`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ClientTool } from "@langchain/core/tools";
|
|
2
2
|
import type { ApiBasedTool } from "../../apiBasedTools.js";
|
|
3
3
|
export declare const ALWAYS_AVAILABLE_API_TOOL_NAMES: readonly ["get_resource"];
|
|
4
|
-
export declare function createAgentTools(customComponentsDir: string, apiBasedTools: Record<string, ApiBasedTool
|
|
4
|
+
export declare function createAgentTools(customComponentsDir: string, apiBasedTools: Record<string, ApiBasedTool>, pluginCustomFolderPaths?: string[]): Promise<ClientTool[]>;
|
|
@@ -12,8 +12,8 @@ import { createFetchToolSchemaTool } from "./fetchToolSchema.js";
|
|
|
12
12
|
import { createApiTool } from "./apiTool.js";
|
|
13
13
|
import { createGetUserLocationTool } from "./getUserLocation.js";
|
|
14
14
|
export const ALWAYS_AVAILABLE_API_TOOL_NAMES = ["get_resource"];
|
|
15
|
-
export function createAgentTools(
|
|
16
|
-
return __awaiter(this,
|
|
15
|
+
export function createAgentTools(customComponentsDir_1, apiBasedTools_1) {
|
|
16
|
+
return __awaiter(this, arguments, void 0, function* (customComponentsDir, apiBasedTools, pluginCustomFolderPaths = []) {
|
|
17
17
|
return [
|
|
18
18
|
...ALWAYS_AVAILABLE_API_TOOL_NAMES.map((toolName) => {
|
|
19
19
|
const apiBasedTool = apiBasedTools[toolName];
|
|
@@ -23,7 +23,7 @@ export function createAgentTools(customComponentsDir, apiBasedTools) {
|
|
|
23
23
|
return createApiTool(toolName, apiBasedTool);
|
|
24
24
|
}),
|
|
25
25
|
createGetUserLocationTool(),
|
|
26
|
-
yield createFetchSkillTool(customComponentsDir),
|
|
26
|
+
yield createFetchSkillTool(customComponentsDir, pluginCustomFolderPaths),
|
|
27
27
|
yield createFetchToolSchemaTool(apiBasedTools),
|
|
28
28
|
];
|
|
29
29
|
});
|
package/dist/agentTurnService.js
CHANGED
|
@@ -86,6 +86,7 @@ export class AgentTurnService {
|
|
|
86
86
|
adminforth,
|
|
87
87
|
apiBasedTools,
|
|
88
88
|
customComponentsDir: (_f = adminforth.config.customization.customComponentsDir) !== null && _f !== void 0 ? _f : "custom",
|
|
89
|
+
pluginCustomFolderPaths: adminforth.activatedPlugins.map((plugin) => plugin.customFolderPath),
|
|
89
90
|
sessionId: input.sessionId,
|
|
90
91
|
turnId: input.turnId,
|
|
91
92
|
currentPage: input.currentPage,
|
|
@@ -3,7 +3,7 @@ import { callAdminForthApi } from '@/utils';
|
|
|
3
3
|
import type { Chat } from '../../chat';
|
|
4
4
|
import type { IAgentSession, ISessionsListItem, IPart } from '../../types';
|
|
5
5
|
import { PRE_SESSION_ID } from './constants';
|
|
6
|
-
import {
|
|
6
|
+
import { i18nInstance } from '@/i18n';
|
|
7
7
|
|
|
8
8
|
type AdminforthLike = {
|
|
9
9
|
confirm(options: { message: string; yes: string; no: string }): Promise<boolean>;
|
|
@@ -42,7 +42,10 @@ export function createAgentSessionManager({
|
|
|
42
42
|
return [...sessionsListToSort].sort((a: ISessionsListItem, b: ISessionsListItem) => b.timestamp.localeCompare(a.timestamp));
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
function t(key: string) {
|
|
46
|
+
return i18nInstance?.global.t(key) ?? key;
|
|
47
|
+
}
|
|
48
|
+
|
|
46
49
|
function saveCurrentSessionInCache() {
|
|
47
50
|
if (currentSession.value) {
|
|
48
51
|
currentSession.value.messages = currentChat.value?.messages.map((m: any) => ({
|
|
@@ -342,4 +345,4 @@ export function createAgentSessionManager({
|
|
|
342
345
|
setCurrentChatStatus,
|
|
343
346
|
updateLastAgentMessage
|
|
344
347
|
};
|
|
345
|
-
}
|
|
348
|
+
}
|
|
@@ -115,7 +115,11 @@
|
|
|
115
115
|
return `${window.location.pathname}${window.location.search}${href}`;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
const
|
|
118
|
+
const isAbsoluteWithScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href);
|
|
119
|
+
const baseUrl = isAbsoluteWithScheme
|
|
120
|
+
? undefined
|
|
121
|
+
: `${window.location.origin}/`;
|
|
122
|
+
const resolvedUrl = new URL(href, baseUrl ?? window.location.href);
|
|
119
123
|
if (resolvedUrl.origin !== window.location.origin) {
|
|
120
124
|
return null;
|
|
121
125
|
}
|