@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.
@@ -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: [...request.tools, ...tools],
77
+ tools: availableTools,
73
78
  });
74
79
  },
75
80
  async wrapToolCall(request, handler) {
@@ -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(customComponentsDir, apiBasedTools);
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,
@@ -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
- export function getProjectPluginSkillsDirectoryPath(customComponentsDir: string) {
87
- return path.resolve(
88
- customComponentsDir,
89
- ...USER_PLUGIN_SKILLS_DIRECTORY_PATH_SEGMENTS,
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
- getProjectPluginSkillsDirectoryPath(customComponentsDir),
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(customComponentsDir: string) {
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(customComponentsDir: string) {
115
- return mergeSkillManifests([
116
- await listProjectSkillManifests(customComponentsDir),
117
- await listBundledSkillManifests(),
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(skillName: string, customComponentsDir: string) {
122
- const manifests = await listSkillManifests(customComponentsDir);
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(skillName: string, customComponentsDir: string) {
133
- const manifest = await loadSkillManifest(skillName, customComponentsDir);
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) {
@@ -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 [primarySkills, defaultSkills] = await Promise.all([
100
- listProjectSkillManifests(customComponentsDir),
101
- listBundledSkillManifests(),
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
- primarySkills.length > 0
113
- ? `You have primary skills set:\n${formatSkills(primarySkills, "skill_name")}`
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 paths and must start with ADMIN_BASE_PATH.",
127
- "Build record links as ADMIN_BASE_PATH + resource/{resourceId}/show/{primary key}. Do not prepend any extra slash before resource.",
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(customComponentsDir: string) {
25
- const availableSkills = await listSkillManifests(customComponentsDir);
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(skillName, customComponentsDir);
37
+ const skillMarkdown = await loadSkillMarkdown(
38
+ skillName,
39
+ customComponentsDir,
40
+ pluginCustomFolderPaths,
41
+ );
32
42
 
33
43
  if (!skillMarkdown) {
34
44
  return [
@@ -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
  }
@@ -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,711 bytes received 921 bytes 3,337,264.00 bytes/sec
66
- total size is 1,663,558 speedup is 1.00
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 { useI18n } from 'vue-i18n';
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
- const { t } = useI18n();
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 resolvedUrl = new URL(href, window.location.href);
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
- return handler(Object.assign(Object.assign({}, request), { tools: [...request.tools, ...tools] }));
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 getProjectPluginSkillsDirectoryPath(customComponentsDir: string): string;
9
- export declare function listBundledSkillManifests(): Promise<AgentSkillManifest[]>;
10
- export declare function listProjectSkillManifests(customComponentsDir: string): Promise<AgentSkillManifest[]>;
11
- export declare function listSkillManifests(customComponentsDir: string): Promise<AgentSkillManifest[]>;
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
- export function getProjectPluginSkillsDirectoryPath(customComponentsDir) {
67
- return path.resolve(customComponentsDir, ...USER_PLUGIN_SKILLS_DIRECTORY_PATH_SEGMENTS);
68
- }
69
- function getProjectSkillDirectoryPaths(customComponentsDir) {
70
- return [
63
+ function getProjectSkillDirectoryPaths(customComponentsDir, pluginCustomFolderPaths = []) {
64
+ return Array.from(new Set([
71
65
  getProjectSkillsDirectoryPath(customComponentsDir),
72
- getProjectPluginSkillsDirectoryPath(customComponentsDir),
73
- ];
66
+ ...normalizePluginSkillDirectoryPaths(pluginCustomFolderPaths),
67
+ ]));
74
68
  }
75
- export function listBundledSkillManifests() {
76
- return __awaiter(this, void 0, void 0, function* () {
77
- return yield listDirectorySkillManifests(PLUGIN_SKILLS_DIRECTORY_PATH);
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 listProjectSkillManifests(customComponentsDir) {
81
- return __awaiter(this, void 0, void 0, function* () {
82
- return mergeSkillManifests(yield Promise.all(getProjectSkillDirectoryPaths(customComponentsDir).map(listDirectorySkillManifests)));
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 listSkillManifests(customComponentsDir) {
86
- return __awaiter(this, void 0, void 0, function* () {
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(skillName, customComponentsDir) {
101
- return __awaiter(this, void 0, void 0, function* () {
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 { listBundledSkillManifests, listProjectSkillManifests, } from "./skills/registry.js";
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 [primarySkills, defaultSkills] = yield Promise.all([
79
- listProjectSkillManifests(customComponentsDir),
80
- listBundledSkillManifests(),
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
- primarySkills.length > 0
90
- ? `You have primary skills set:\n${formatSkills(primarySkills, "skill_name")}`
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 paths and must start with ADMIN_BASE_PATH.",
104
- "Build record links as ADMIN_BASE_PATH + resource/{resourceId}/show/{primary key}. Do not prepend any extra slash before resource.",
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(customComponentsDir) {
25
- return __awaiter(this, void 0, void 0, function* () {
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>): Promise<ClientTool[]>;
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(customComponentsDir, apiBasedTools) {
16
- return __awaiter(this, void 0, void 0, function* () {
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
  });
@@ -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 { useI18n } from 'vue-i18n';
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
- const { t } = useI18n();
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 resolvedUrl = new URL(href, window.location.href);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.47.2",
3
+ "version": "1.48.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",