@adminforth/agent 2.0.10 → 2.2.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.
Files changed (201) hide show
  1. package/README.md +333 -10
  2. package/dist/application/ports.d.ts +66 -0
  3. package/dist/application/runTurnUseCase.d.ts +71 -0
  4. package/dist/application/runTurnUseCase.js +364 -0
  5. package/dist/custom/ChatFooter.vue +58 -30
  6. package/dist/custom/SteerDebugPanel.vue +45 -0
  7. package/dist/custom/SteerQueue.vue +54 -0
  8. package/dist/custom/composables/agentStore/constants.ts +1 -0
  9. package/dist/custom/composables/agentStore/useAgentSessions.ts +35 -16
  10. package/dist/custom/composables/agentStore/useAgentSteerQueue.ts +114 -0
  11. package/dist/custom/composables/useAgentStore.ts +46 -1
  12. package/dist/custom/conversation_area/MessageRenderer.vue +7 -1
  13. package/dist/custom/speech_recognition_frontend/AudioLines.vue +1 -1
  14. package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +3 -3
  15. package/dist/{agentEvents.d.ts → domain/agentEvents.d.ts} +5 -1
  16. package/dist/domain/steerBuffer.d.ts +33 -0
  17. package/dist/domain/steerBuffer.js +51 -0
  18. package/dist/{agent → domain}/systemPrompt.js +1 -1
  19. package/dist/{agent/turn → domain}/turnTypes.d.ts +41 -37
  20. package/dist/{agent/turn/VegaLiteStreamBuffer.d.ts → domain/vegaLiteStreamBuffer.d.ts} +1 -1
  21. package/dist/index.d.ts +4 -2
  22. package/dist/index.js +49 -35
  23. package/dist/{agent/runtime/AgentContext.d.ts → llm/agentContext.d.ts} +3 -3
  24. package/dist/{agent/simpleAgent.d.ts → llm/agentModels.d.ts} +18 -16
  25. package/dist/llm/agentModels.js +65 -0
  26. package/dist/{agent/runtime/AgentRuntime.d.ts → llm/agentRuntime.d.ts} +14 -2
  27. package/dist/{agent/runtime/AgentRuntime.js → llm/agentRuntime.js} +41 -6
  28. package/dist/llm/langGraphLlm.d.ts +25 -0
  29. package/dist/llm/langGraphLlm.js +54 -0
  30. package/dist/{agent/middleware/apiBasedTools.d.ts → llm/middleware/apiToolsMiddleware.d.ts} +1 -1
  31. package/dist/{agent/middleware/apiBasedTools.js → llm/middleware/apiToolsMiddleware.js} +8 -14
  32. package/dist/{agent → llm}/middleware/sequenceDebug.d.ts +1 -1
  33. package/dist/llm/middleware/steerMiddleware.d.ts +21 -0
  34. package/dist/llm/middleware/steerMiddleware.js +50 -0
  35. package/dist/{agent/models/AgentModelFactory.d.ts → llm/modelFactory.d.ts} +1 -1
  36. package/dist/{agent/models/AgentModelFactory.js → llm/modelFactory.js} +1 -1
  37. package/dist/llm/streamAdapter.d.ts +18 -0
  38. package/dist/llm/streamAdapter.js +117 -0
  39. package/dist/{sessionStore.d.ts → persistence/sessionStore.d.ts} +19 -2
  40. package/dist/{sessionStore.js → persistence/sessionStore.js} +53 -0
  41. package/dist/{agent/tools/AgentToolProvider.d.ts → tools/agentToolProvider.d.ts} +1 -1
  42. package/dist/{agent/tools/AgentToolProvider.js → tools/agentToolProvider.js} +1 -1
  43. package/dist/{apiBasedTools.js → tools/apiBasedTools.js} +0 -3
  44. package/dist/{agent/tools → tools}/apiTool.d.ts +1 -1
  45. package/dist/{agent/tools → tools}/fetchSkill.js +1 -1
  46. package/dist/{agent/tools → tools}/fetchToolSchema.d.ts +1 -1
  47. package/dist/{agent/tools → tools}/index.d.ts +1 -1
  48. package/dist/{agent/tools → tools}/navigateUser.d.ts +3 -3
  49. package/dist/{endpoints → transport/http}/context.d.ts +12 -4
  50. package/dist/transport/http/context.js +1 -0
  51. package/dist/{endpoints/core.js → transport/http/coreEndpoints.js} +23 -3
  52. package/dist/{endpoints/sessions.js → transport/http/sessionEndpoints.js} +36 -1
  53. package/dist/transport/sse/sseWriter.d.ts +29 -0
  54. package/dist/{surfaces/web-sse/createSseEventEmitter.js → transport/sse/sseWriter.js} +27 -0
  55. package/dist/{chatSurfaceService.d.ts → transport/surfaces/chatSurfaceService.d.ts} +3 -3
  56. package/dist/{chatSurfaceService.js → transport/surfaces/chatSurfaceService.js} +7 -5
  57. package/dist/{agent/speech/SpeechTurnService.d.ts → transport/surfaces/speechTurnService.d.ts} +1 -1
  58. package/dist/{agent/speech/SpeechTurnService.js → transport/surfaces/speechTurnService.js} +2 -2
  59. package/dist/types.d.ts +10 -4
  60. package/package.json +11 -2
  61. package/.woodpecker/buildRelease.sh +0 -13
  62. package/.woodpecker/buildSlackNotify.sh +0 -46
  63. package/.woodpecker/release.yml +0 -57
  64. package/agent/checkpointer.ts +0 -329
  65. package/agent/languageDetect.ts +0 -92
  66. package/agent/middleware/apiBasedTools.ts +0 -174
  67. package/agent/middleware/openAiResponsesContinuation.ts +0 -92
  68. package/agent/middleware/sequenceDebug.ts +0 -429
  69. package/agent/models/AgentModeResolver.ts +0 -9
  70. package/agent/models/AgentModelFactory.ts +0 -28
  71. package/agent/runtime/AgentContext.ts +0 -30
  72. package/agent/runtime/AgentRuntime.ts +0 -89
  73. package/agent/simpleAgent.ts +0 -199
  74. package/agent/skills/registry.ts +0 -162
  75. package/agent/speech/SpeechTurnService.ts +0 -179
  76. package/agent/systemPrompt.ts +0 -133
  77. package/agent/toolCallEvents.ts +0 -135
  78. package/agent/tools/AgentToolProvider.ts +0 -28
  79. package/agent/tools/apiTool.ts +0 -66
  80. package/agent/tools/fetchSkill.ts +0 -68
  81. package/agent/tools/fetchToolSchema.ts +0 -47
  82. package/agent/tools/getUserLocation.ts +0 -45
  83. package/agent/tools/index.ts +0 -31
  84. package/agent/tools/navigateUser.ts +0 -210
  85. package/agent/turn/TurnContextBuilder.ts +0 -36
  86. package/agent/turn/TurnLifecycleService.ts +0 -47
  87. package/agent/turn/TurnPersistenceService.ts +0 -33
  88. package/agent/turn/TurnPromptBuilder.ts +0 -51
  89. package/agent/turn/TurnStreamConsumer.ts +0 -69
  90. package/agent/turn/VegaLiteStreamBuffer.ts +0 -90
  91. package/agent/turn/turnTypes.ts +0 -100
  92. package/agentEvents.ts +0 -75
  93. package/agentTurnService.ts +0 -314
  94. package/apiBasedTools.ts +0 -712
  95. package/build.log +0 -67
  96. package/chatSurfaceService.ts +0 -319
  97. package/custom/ChatFooter.vue +0 -173
  98. package/custom/ChatHeader.vue +0 -78
  99. package/custom/ChatSurface.vue +0 -160
  100. package/custom/CustomAutoScrollContainer.vue +0 -164
  101. package/custom/SessionsHistory.vue +0 -88
  102. package/custom/chat.ts +0 -82
  103. package/custom/composables/agentAudio/utils.ts +0 -220
  104. package/custom/composables/agentStore/constants.ts +0 -19
  105. package/custom/composables/agentStore/pageContext.ts +0 -8
  106. package/custom/composables/agentStore/useAgentChat.ts +0 -241
  107. package/custom/composables/agentStore/useAgentPlaceholder.ts +0 -142
  108. package/custom/composables/agentStore/useAgentSessions.ts +0 -350
  109. package/custom/composables/useAgentAudio.ts +0 -272
  110. package/custom/composables/useAgentStore.ts +0 -510
  111. package/custom/composables/useAgentTransitions.ts +0 -58
  112. package/custom/conversation_area/ConversationArea.vue +0 -301
  113. package/custom/conversation_area/MessageRenderer.vue +0 -49
  114. package/custom/conversation_area/ProcessingTimeline.vue +0 -286
  115. package/custom/conversation_area/ReasoningRenderer.vue +0 -79
  116. package/custom/conversation_area/SystemMessageRenderer.vue +0 -28
  117. package/custom/conversation_area/TextRenderer.vue +0 -182
  118. package/custom/conversation_area/ThreeDotsAnimation.vue +0 -35
  119. package/custom/conversation_area/ToolApprovalRenderer.vue +0 -98
  120. package/custom/conversation_area/ToolRenderer.vue +0 -178
  121. package/custom/conversation_area/ToolsGroup.vue +0 -59
  122. package/custom/env.d.ts +0 -7
  123. package/custom/incremark_code_renderers/IncremarkShikiCodeBlock.vue +0 -393
  124. package/custom/incremark_code_renderers/incremarkCodeHighlight.ts +0 -285
  125. package/custom/incremark_code_renderers/incremarkRenderer.ts +0 -653
  126. package/custom/incremark_code_renderers/renderIncremarkMarkdown.ts +0 -118
  127. package/custom/package.json +0 -30
  128. package/custom/pnpm-lock.yaml +0 -2394
  129. package/custom/public/agentAudio/agent-processing.mp3 +0 -0
  130. package/custom/skills/analyze_data/SKILL.md +0 -25
  131. package/custom/skills/charts/SKILL.md +0 -193
  132. package/custom/skills/fetch_data/SKILL.md +0 -31
  133. package/custom/skills/mutate_data/SKILL.md +0 -121
  134. package/custom/speech_recognition_frontend/AudioLines.vue +0 -43
  135. package/custom/speech_recognition_frontend/MicrophoneButon.vue +0 -185
  136. package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +0 -22
  137. package/custom/speech_recognition_frontend/voiceActivityDetection.ts +0 -62
  138. package/custom/tsconfig.json +0 -15
  139. package/custom/types.ts +0 -108
  140. package/custom/utils.ts +0 -38
  141. package/dist/agent/middleware/openAiResponsesContinuation.d.ts +0 -1
  142. package/dist/agent/middleware/openAiResponsesContinuation.js +0 -66
  143. package/dist/agent/models/AgentModeResolver.d.ts +0 -9
  144. package/dist/agent/models/AgentModeResolver.js +0 -9
  145. package/dist/agent/simpleAgent.js +0 -118
  146. package/dist/agent/turn/TurnContextBuilder.d.ts +0 -14
  147. package/dist/agent/turn/TurnContextBuilder.js +0 -31
  148. package/dist/agent/turn/TurnLifecycleService.d.ts +0 -24
  149. package/dist/agent/turn/TurnLifecycleService.js +0 -47
  150. package/dist/agent/turn/TurnPersistenceService.d.ts +0 -13
  151. package/dist/agent/turn/TurnPersistenceService.js +0 -35
  152. package/dist/agent/turn/TurnPromptBuilder.d.ts +0 -19
  153. package/dist/agent/turn/TurnPromptBuilder.js +0 -43
  154. package/dist/agent/turn/TurnStreamConsumer.d.ts +0 -11
  155. package/dist/agent/turn/TurnStreamConsumer.js +0 -84
  156. package/dist/agentTurnService.d.ts +0 -24
  157. package/dist/agentTurnService.js +0 -269
  158. package/dist/surfaces/web-sse/createSseEventEmitter.d.ts +0 -14
  159. package/endpoints/chatSurfaces.ts +0 -66
  160. package/endpoints/context.ts +0 -52
  161. package/endpoints/core.ts +0 -181
  162. package/endpoints/sessions.ts +0 -183
  163. package/errors.ts +0 -10
  164. package/index.ts +0 -192
  165. package/pnpm-workspace.yaml +0 -4
  166. package/sanitizeSpeechText.ts +0 -32
  167. package/sessionStore.ts +0 -105
  168. package/surfaces/web-sse/createSseEventEmitter.ts +0 -311
  169. package/tsconfig.json +0 -14
  170. package/types.ts +0 -127
  171. /package/dist/{agent/turn/turnTypes.js → application/ports.js} +0 -0
  172. /package/dist/{agentEvents.js → domain/agentEvents.js} +0 -0
  173. /package/dist/{agent → domain}/languageDetect.d.ts +0 -0
  174. /package/dist/{agent → domain}/languageDetect.js +0 -0
  175. /package/dist/{agent → domain}/systemPrompt.d.ts +0 -0
  176. /package/dist/{agent → domain}/toolCallEvents.d.ts +0 -0
  177. /package/dist/{agent → domain}/toolCallEvents.js +0 -0
  178. /package/dist/{endpoints/context.js → domain/turnTypes.js} +0 -0
  179. /package/dist/{agent/turn/VegaLiteStreamBuffer.js → domain/vegaLiteStreamBuffer.js} +0 -0
  180. /package/dist/{agent/runtime/AgentContext.js → llm/agentContext.js} +0 -0
  181. /package/dist/{agent → llm}/middleware/sequenceDebug.js +0 -0
  182. /package/dist/{agent/checkpointer.d.ts → persistence/checkpointStore.d.ts} +0 -0
  183. /package/dist/{agent/checkpointer.js → persistence/checkpointStore.js} +0 -0
  184. /package/dist/{errors.d.ts → shared/errors.d.ts} +0 -0
  185. /package/dist/{errors.js → shared/errors.js} +0 -0
  186. /package/dist/{sanitizeSpeechText.d.ts → shared/sanitizeSpeechText.d.ts} +0 -0
  187. /package/dist/{sanitizeSpeechText.js → shared/sanitizeSpeechText.js} +0 -0
  188. /package/dist/{apiBasedTools.d.ts → tools/apiBasedTools.d.ts} +0 -0
  189. /package/dist/{agent/tools → tools}/apiTool.js +0 -0
  190. /package/dist/{agent/tools → tools}/fetchSkill.d.ts +0 -0
  191. /package/dist/{agent/tools → tools}/fetchToolSchema.js +0 -0
  192. /package/dist/{agent/tools → tools}/getUserLocation.d.ts +0 -0
  193. /package/dist/{agent/tools → tools}/getUserLocation.js +0 -0
  194. /package/dist/{agent/tools → tools}/index.js +0 -0
  195. /package/dist/{agent/tools → tools}/navigateUser.js +0 -0
  196. /package/dist/{agent → tools}/skills/registry.d.ts +0 -0
  197. /package/dist/{agent → tools}/skills/registry.js +0 -0
  198. /package/dist/{endpoints/chatSurfaces.d.ts → transport/http/chatSurfaceEndpoints.d.ts} +0 -0
  199. /package/dist/{endpoints/chatSurfaces.js → transport/http/chatSurfaceEndpoints.js} +0 -0
  200. /package/dist/{endpoints/core.d.ts → transport/http/coreEndpoints.d.ts} +0 -0
  201. /package/dist/{endpoints/sessions.d.ts → transport/http/sessionEndpoints.d.ts} +0 -0
@@ -1,133 +0,0 @@
1
- import type { AdminForthResource, AdminUser, IAdminForth } from "adminforth";
2
- import type { DetectedLanguage } from "./languageDetect.js";
3
- import {
4
- listProjectSkillManifests,
5
- type AgentSkillManifest,
6
- } from "./skills/registry.js";
7
-
8
- export const DEFAULT_AGENT_SYSTEM_PROMPT = [
9
- "You are helpful AI Assistant for Admin Panel.",
10
-
11
- // about admin
12
- "Admin panel has resources which represent some physical data storage (e.g. table/collection), each resource defines list of columns.",
13
- "Each resource stores data records. Record represents a data item of resource.",
14
-
15
- //about user
16
- "Assume user is not technical so does not talk to him in terms of API calls, databases/sql/json etc.",
17
-
18
- // prevent extra talk
19
- "Try to achieve user's goal with as few steps as possible. Talk with him only when you need some important decision, otherwise act immediately and call tools asap",
20
-
21
- // tone of voice
22
- "Be warm, friendly, and sincere.",
23
- "Keep responses short, clear, and practical.",
24
- "Answer only what is needed.",
25
- "Do not add extra explanations or suggestions unless the user asks.",
26
- "Adapt to the user's tone and style of speaking, mirroring their vibe and wording.",
27
- "if the user speaks casually, you should respond casually too",
28
- "Before calling a dangerous tool, briefly describe the exact action, target, and important changes in chat.",
29
- "Do not ask the user for textual confirmation; dangerous tools are approved by the runtime approval UI.",
30
- ].join(" ");
31
-
32
- export function appendCustomSystemPrompt(
33
- systemPrompt: string,
34
- customSystemPrompt?: string,
35
- ) {
36
- const normalizedCustomSystemPrompt = customSystemPrompt?.trim();
37
-
38
- if (!normalizedCustomSystemPrompt) {
39
- return systemPrompt;
40
- }
41
-
42
- return `${systemPrompt}\n\n${normalizedCustomSystemPrompt}`;
43
- }
44
-
45
- function formatLanguagePrompt(language: DetectedLanguage | null) {
46
- if (!language || language.ambiguous) {
47
- return "Respond in the user's language.";
48
- }
49
-
50
- return `Respond in ${language.language} (${language.code}).`;
51
- }
52
-
53
- function formatAdminUserPrompt(adminUser: AdminUser, usernameField: string) {
54
- const adminUserContext = {
55
- id: adminUser.pk,
56
- email: adminUser.dbUser[usernameField],
57
- };
58
- return [
59
- "Current admin user context:",
60
- JSON.stringify(adminUserContext, null, 2),
61
- "Use this admin user email when the user asks to send information to themselves, the current admin, or the logged-in user.",
62
- ].join("\n");
63
- }
64
-
65
- export function buildAgentTurnSystemPrompt(input: {
66
- agentSystemPrompt: string;
67
- adminUser: AdminUser;
68
- usernameField: string;
69
- userLanguage: DetectedLanguage | null;
70
- chatSurface?: string;
71
- }) {
72
- return [
73
- input.agentSystemPrompt,
74
- formatAdminUserPrompt(input.adminUser, input.usernameField),
75
- input.chatSurface
76
- ? `Current chat surface: ${input.chatSurface}. The user is not in the AdminForth web UI, so tools cannot move their browser. When navigate_user returns a link, send that link to the user.`
77
- : "",
78
- formatLanguagePrompt(input.userLanguage),
79
- ].filter(Boolean).join("\n\n");
80
- }
81
-
82
- function formatResources(resources: AdminForthResource[]) {
83
- return resources
84
- .map((resource) => `- resourceId: ${resource.resourceId}\n label: ${resource.label}`)
85
- .join("\n");
86
- }
87
-
88
- function formatSkills(skills: AgentSkillManifest[], label: "skill_name" | "tool_name") {
89
- return skills
90
- .map((skill) => `- ${label}: ${skill.name}\n description: ${skill.description}`)
91
- .join("\n");
92
- }
93
-
94
- export async function buildAgentSystemPrompt(
95
- adminforth: IAdminForth,
96
- hiddenResourceIds: Iterable<string> = [],
97
- ) {
98
- const customComponentsDir = adminforth.config.customization.customComponentsDir ?? "custom";
99
- const pluginCustomFolderPaths = adminforth.activatedPlugins
100
- .map((plugin) => plugin.customFolderPath);
101
- const skills = await listProjectSkillManifests(
102
- customComponentsDir,
103
- pluginCustomFolderPaths,
104
- );
105
- const adminBasePath = adminforth.config.baseUrlSlashed;
106
- const hiddenResourceIdSet = new Set(hiddenResourceIds);
107
- const visibleResources = adminforth.config.resources.filter(
108
- (resource) => !hiddenResourceIdSet.has(resource.resourceId),
109
- );
110
- const sections = [
111
- DEFAULT_AGENT_SYSTEM_PROMPT,
112
- `ADMIN_BASE_PATH: ${adminBasePath}`,
113
- `List of resources:\n${formatResources(visibleResources)}`,
114
- skills.length > 0
115
- ? `You have skills set:\n${formatSkills(skills, "skill_name")}`
116
- : "",
117
- "Before using any skill, call fetch_skill to load its full instructions.",
118
- "The fetched skill response starts with 'Tools mentioned in this skill'. Read that list first.",
119
- "You can use get_resource immediately to inspect resource structure and column names.",
120
- "If the user wants to create, update, delete, or run actions on records, load mutate_data first.",
121
- "If the user wants to fetch records, load fetch_data first. If the user wants analytics or charts, load analyze_data first.",
122
- "Only call fetch_tool_schema for tool names that are explicitly mentioned in a fetched skill and are not already available as base tools.",
123
- "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
- "For example: for record creation load mutate_data, read its tool list, call fetch_tool_schema for create_record, describe the planned record, and then use create_record.",
125
- "When fetch_tool_schema succeeds, that tool becomes available on the next step.",
126
- "All admin links must be root-relative and start with '/'.",
127
- "Build record links as '/resource/{resourceId}/show/{primary key}'. Never use bare 'resource/{resourceId}/show/{primary key}' without the leading slash.",
128
- "When the user asks to open or show a page in the AdminForth UI, call navigate_user instead of only sending a link.",
129
- "Try to call as many tools as possible in parallel in one step.",
130
- ];
131
-
132
- return sections.filter(Boolean).join("\n\n");
133
- }
@@ -1,135 +0,0 @@
1
- import { randomUUID } from "crypto";
2
- import YAML from "yaml";
3
-
4
- export type ToolCallEvent =
5
- | {
6
- toolCallId: string;
7
- toolName: string;
8
- toolInfo?: string;
9
- phase: "start";
10
- input: string;
11
- }
12
- | {
13
- toolCallId: string;
14
- toolName: string;
15
- phase: "end";
16
- durationMs: number;
17
- output: string | null;
18
- error: string | null;
19
- };
20
-
21
- export type ToolCallEventSink = (event: ToolCallEvent) => void;
22
-
23
- const TOOL_MESSAGE_DEBUG_KEYS = new Set([
24
- "metadata",
25
- "additional_kwargs",
26
- "response_metadata",
27
- ]);
28
-
29
- function getToolCallDebugPayload(outputRecord: Record<string, unknown>) {
30
- const lcKwargs =
31
- typeof outputRecord.lc_kwargs === "object" && outputRecord.lc_kwargs !== null
32
- ? outputRecord.lc_kwargs as Record<string, unknown>
33
- : null;
34
-
35
- if (lcKwargs && "tool_call_id" in lcKwargs) {
36
- return lcKwargs;
37
- }
38
-
39
- if ("tool_call_id" in outputRecord) {
40
- return outputRecord;
41
- }
42
-
43
- return null;
44
- }
45
-
46
- function sanitizeToolCallOutputForDebug(output: unknown) {
47
- if (typeof output !== "object" || output === null) {
48
- return output;
49
- }
50
-
51
- const outputRecord = output as Record<string, unknown>;
52
- const debugPayload = getToolCallDebugPayload(outputRecord);
53
-
54
- if (!debugPayload) {
55
- return output;
56
- }
57
-
58
- return Object.fromEntries(
59
- Object.entries(debugPayload).filter(([key]) => !TOOL_MESSAGE_DEBUG_KEYS.has(key)),
60
- );
61
- }
62
-
63
- function serializeErrorForDebug(error: unknown): unknown {
64
- if (!(error instanceof Error)) {
65
- return error;
66
- }
67
-
68
- const errorWithCause = error as Error & { cause?: unknown };
69
- const serialized: Record<string, unknown> = {
70
- name: error.name,
71
- message: error.message,
72
- };
73
-
74
- if (error.stack) {
75
- serialized.stack = error.stack;
76
- }
77
-
78
- if (errorWithCause.cause !== undefined) {
79
- serialized.cause = serializeErrorForDebug(errorWithCause.cause);
80
- }
81
-
82
- for (const key of Object.getOwnPropertyNames(error)) {
83
- if (key in serialized) {
84
- continue;
85
- }
86
-
87
- serialized[key] = (error as unknown as Record<string, unknown>)[key];
88
- }
89
-
90
- return serialized;
91
- }
92
-
93
- export function createToolCallTracker(params: {
94
- emit: ToolCallEventSink;
95
- toolCallId?: string;
96
- toolName: string;
97
- toolInfo?: string;
98
- input?: Record<string, unknown>;
99
- startedAt?: number;
100
- }) {
101
- const toolCallId = params.toolCallId ?? randomUUID();
102
- const startedAt = params.startedAt ?? Date.now();
103
-
104
- return {
105
- start() {
106
- params.emit({
107
- toolCallId,
108
- toolName: params.toolName,
109
- toolInfo: params.toolInfo,
110
- phase: "start",
111
- input: YAML.stringify(params.input ?? {}),
112
- });
113
- },
114
- finishSuccess(output: unknown) {
115
- params.emit({
116
- toolCallId,
117
- toolName: params.toolName,
118
- phase: "end",
119
- durationMs: Date.now() - startedAt,
120
- output: YAML.stringify(sanitizeToolCallOutputForDebug(output)).trimEnd(),
121
- error: null,
122
- });
123
- },
124
- finishError(error: unknown) {
125
- params.emit({
126
- toolCallId,
127
- toolName: params.toolName,
128
- phase: "end",
129
- durationMs: Date.now() - startedAt,
130
- output: null,
131
- error: YAML.stringify(serializeErrorForDebug(error)).trimEnd(),
132
- });
133
- },
134
- };
135
- }
@@ -1,28 +0,0 @@
1
- import type { IAdminForth } from "adminforth";
2
- import { prepareApiBasedTools } from "../../apiBasedTools.js";
3
- import type { ApiBasedTool } from "../../apiBasedTools.js";
4
- import { createAgentTools } from "./index.js";
5
-
6
- export class AgentToolProvider {
7
- constructor(
8
- private readonly getAdminforth: () => IAdminForth,
9
- private readonly getInternalAgentResourceIds: () => string[],
10
- ) {}
11
-
12
- getApiBasedTools(): Record<string, ApiBasedTool> {
13
- return prepareApiBasedTools(
14
- this.getAdminforth(),
15
- this.getInternalAgentResourceIds(),
16
- );
17
- }
18
-
19
- async getTools(apiBasedTools: Record<string, ApiBasedTool>) {
20
- const adminforth = this.getAdminforth();
21
-
22
- return createAgentTools(
23
- adminforth.config.customization.customComponentsDir ?? "custom",
24
- apiBasedTools,
25
- adminforth.activatedPlugins.map((plugin) => plugin.customFolderPath),
26
- );
27
- }
28
- }
@@ -1,66 +0,0 @@
1
- import { tool } from "langchain";
2
- import type { ApiBasedTool } from "../../apiBasedTools.js";
3
-
4
- const emptyToolSchema = {
5
- type: "object",
6
- properties: {},
7
- additionalProperties: true,
8
- } as const;
9
-
10
- function normalizeToolInputSchema(inputSchema: unknown) {
11
- if (!inputSchema || typeof inputSchema !== "object" || Array.isArray(inputSchema)) {
12
- return emptyToolSchema;
13
- }
14
-
15
- const schema = JSON.parse(JSON.stringify(inputSchema)) as Record<string, unknown>;
16
-
17
- if (schema.type !== "object") {
18
- return emptyToolSchema;
19
- }
20
-
21
- const notes: string[] = [];
22
-
23
- if ("if" in schema || "then" in schema || "else" in schema || "allOf" in schema) {
24
- delete schema.if;
25
- delete schema.then;
26
- delete schema.else;
27
- delete schema.allOf;
28
- notes.push("Runtime applies additional conditional validation rules.");
29
- }
30
-
31
- if ("oneOf" in schema || "anyOf" in schema || "not" in schema || "enum" in schema) {
32
- delete schema.oneOf;
33
- delete schema.anyOf;
34
- delete schema.not;
35
- delete schema.enum;
36
- notes.push("Top-level composite validation rules are omitted for tool compatibility.");
37
- }
38
-
39
- if (notes.length > 0) {
40
- schema.description = typeof schema.description === "string"
41
- ? `${schema.description}\n\n${notes.join(" ")}`
42
- : notes.join(" ");
43
- }
44
-
45
- return schema;
46
- }
47
-
48
- export function createApiTool(toolName: string, apiBasedTool: ApiBasedTool) {
49
- return tool(
50
- async (input, runtime) => {
51
- const normalizedInput = (input ?? {}) as Record<string, unknown>;
52
- return apiBasedTool.call({
53
- adminUser: runtime.context.adminUser,
54
- abortSignal: runtime.context.abortSignal,
55
- inputs: normalizedInput,
56
- userTimeZone: runtime.context.userTimeZone,
57
- });
58
- },
59
- {
60
- name: toolName,
61
- description: apiBasedTool.description ?? `${toolName} tool`,
62
- schema: normalizeToolInputSchema(apiBasedTool.input_schema),
63
- verboseParsingErrors: true,
64
- },
65
- );
66
- }
@@ -1,68 +0,0 @@
1
- import { tool } from "langchain";
2
- import { z } from "zod";
3
- import {
4
- listSkillManifests,
5
- loadSkillMarkdown,
6
- type AgentSkillManifest,
7
- } from "../skills/registry.js";
8
-
9
- const fetchSkillSchema = z.object({
10
- skillName: z
11
- .string()
12
- .describe(
13
- "Name of the custom AdminForth skill to load, for example fetch_data or mutate_data.",
14
- ),
15
- });
16
-
17
- function serializeSkillManifests(skillManifests: AgentSkillManifest[]) {
18
- return skillManifests.map((skill) => ({
19
- name: skill.name,
20
- description: skill.description,
21
- }));
22
- }
23
-
24
- export async function createFetchSkillTool(
25
- customComponentsDir: string,
26
- pluginCustomFolderPaths: string[] = [],
27
- ) {
28
- const availableSkills = await listSkillManifests(
29
- customComponentsDir,
30
- pluginCustomFolderPaths,
31
- );
32
- const availableSkillNames = availableSkills.map((skill) => skill.name);
33
-
34
- return tool(
35
- async ({ skillName }) => {
36
- try {
37
- const skillMarkdown = await loadSkillMarkdown(
38
- skillName,
39
- customComponentsDir,
40
- pluginCustomFolderPaths,
41
- );
42
-
43
- if (!skillMarkdown) {
44
- return [
45
- `Skill "${skillName}" not found.`,
46
- "Available skills:",
47
- JSON.stringify(serializeSkillManifests(availableSkills), null, 2),
48
- ].join("\n");
49
- }
50
-
51
- return skillMarkdown;
52
- } catch (error) {
53
- return `Failed to load skill "${skillName}": ${
54
- error instanceof Error ? error.message : String(error)
55
- }`;
56
- }
57
- },
58
- {
59
- name: "fetch_skill",
60
- description: `Fetch the raw SKILL.md content for a custom AdminForth skill by name.${
61
- availableSkillNames.length > 0
62
- ? ` Available skills: ${availableSkillNames.join(", ")}.`
63
- : ""
64
- }`,
65
- schema: fetchSkillSchema,
66
- },
67
- );
68
- }
@@ -1,47 +0,0 @@
1
- import { tool } from "langchain";
2
- import { z } from "zod";
3
- import type { ApiBasedTool } from "../../apiBasedTools.js";
4
-
5
- const fetchToolSchemaSchema = z.object({
6
- toolName: z
7
- .string()
8
- .describe("Name of the API-based tool to load, for example get_resource."),
9
- });
10
-
11
- export async function createFetchToolSchemaTool(
12
- apiBasedTools: Record<string, ApiBasedTool>,
13
- ) {
14
- return tool(
15
- async ({ toolName }) => {
16
- const toolDefinition = apiBasedTools[toolName];
17
-
18
- if (!toolDefinition) {
19
- return JSON.stringify(
20
- {
21
- status: 404,
22
- error: "TOOL_NOT_FOUND",
23
- message: `Tool "${toolName}" not found.`,
24
- },
25
- null,
26
- 2,
27
- );
28
- }
29
-
30
- return JSON.stringify(
31
- {
32
- status: 200,
33
- name: toolName,
34
- loaded: true,
35
- },
36
- null,
37
- 2,
38
- );
39
- },
40
- {
41
- name: "fetch_tool_schema",
42
- description:
43
- "Fetch the schema for an API-based AdminForth tool by name and load it for later use. Use this right after fetch_skill when the skill mentions non-base tools.",
44
- schema: fetchToolSchemaSchema,
45
- },
46
- );
47
- }
@@ -1,45 +0,0 @@
1
- import { tool } from "langchain";
2
- import { z } from "zod";
3
-
4
- export type CurrentPageContext = {
5
- path: string;
6
- fullPath: string;
7
- title: string;
8
- url: string;
9
- };
10
-
11
- const getUserLocationSchema = z.object({});
12
-
13
- export function createGetUserLocationTool() {
14
- return tool(
15
- async (_input, runtime) => {
16
- const currentPage = (runtime.context as { currentPage?: CurrentPageContext }).currentPage;
17
-
18
- if (!currentPage) {
19
- return JSON.stringify(
20
- {
21
- status: 404,
22
- message: "Current user location is not available.",
23
- },
24
- null,
25
- 2,
26
- );
27
- }
28
-
29
- return JSON.stringify(
30
- {
31
- status: 200,
32
- location: currentPage,
33
- },
34
- null,
35
- 2,
36
- );
37
- },
38
- {
39
- name: "get_user_location",
40
- description:
41
- "Get the user's current location in the AdminForth UI, including current page path, full path, title, and URL. Call this tool when you do not understand what the user is referring to, especially when they say here, this page, current page, opened page, or otherwise rely on page context.",
42
- schema: getUserLocationSchema,
43
- },
44
- );
45
- }
@@ -1,31 +0,0 @@
1
- import type { ClientTool } from "@langchain/core/tools";
2
- import { createFetchSkillTool } from "./fetchSkill.js";
3
- import { createFetchToolSchemaTool } from "./fetchToolSchema.js";
4
- import type { ApiBasedTool } from "../../apiBasedTools.js";
5
- import { createApiTool } from "./apiTool.js";
6
- import { createGetUserLocationTool } from "./getUserLocation.js";
7
- import { createNavigateUserTool } from "./navigateUser.js";
8
-
9
- export const ALWAYS_AVAILABLE_API_TOOL_NAMES = ["get_resource"] as const;
10
-
11
- export async function createAgentTools(
12
- customComponentsDir: string,
13
- apiBasedTools: Record<string, ApiBasedTool>,
14
- pluginCustomFolderPaths: string[] = [],
15
- ): Promise<ClientTool[]> {
16
- return [
17
- ...ALWAYS_AVAILABLE_API_TOOL_NAMES.map((toolName) => {
18
- const apiBasedTool = apiBasedTools[toolName];
19
-
20
- if (!apiBasedTool) {
21
- throw new Error(`Required base API tool "${toolName}" is missing.`);
22
- }
23
-
24
- return createApiTool(toolName, apiBasedTool);
25
- }),
26
- createGetUserLocationTool(),
27
- createNavigateUserTool(),
28
- await createFetchSkillTool(customComponentsDir, pluginCustomFolderPaths),
29
- await createFetchToolSchemaTool(apiBasedTools),
30
- ];
31
- }