@adminforth/agent 1.37.0 → 1.39.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 (55) hide show
  1. package/agent/languageDetect.ts +0 -8
  2. package/agent/simpleAgent.ts +5 -5
  3. package/agent/systemPrompt.ts +35 -4
  4. package/agent/toolCallEvents.ts +31 -2
  5. package/agent/tools/apiTool.ts +1 -1
  6. package/agentResponseEvents.ts +197 -0
  7. package/apiBasedTools.ts +118 -284
  8. package/build.log +13 -2
  9. package/custom/ChatSurface.vue +31 -21
  10. package/custom/composables/agentStore/constants.ts +8 -1
  11. package/custom/composables/agentStore/useAgentSessions.ts +85 -12
  12. package/custom/composables/useAgentAudio.ts +401 -0
  13. package/custom/composables/useAgentStore.ts +52 -5
  14. package/custom/conversation_area/ConversationArea.vue +1 -1
  15. package/custom/conversation_area/MessageRenderer.vue +12 -1
  16. package/custom/conversation_area/SystemMessageRenderer.vue +28 -0
  17. package/custom/conversation_area/TextRenderer.vue +4 -3
  18. package/custom/conversation_area/ToolRenderer.vue +1 -1
  19. package/custom/package.json +2 -1
  20. package/custom/pnpm-lock.yaml +29 -0
  21. package/custom/public/agentAudio/agent-processing.mp3 +0 -0
  22. package/custom/speech_recognition_frontend/AudioLines.vue +97 -0
  23. package/custom/speech_recognition_frontend/MicrophoneButon.vue +157 -0
  24. package/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +22 -0
  25. package/custom/speech_recognition_frontend/voiceActivityDetection.ts +151 -0
  26. package/custom/types.ts +52 -2
  27. package/dist/agent/languageDetect.js +0 -6
  28. package/dist/agent/simpleAgent.js +4 -3
  29. package/dist/agent/systemPrompt.js +24 -3
  30. package/dist/agent/toolCallEvents.js +24 -2
  31. package/dist/agent/tools/apiTool.js +1 -1
  32. package/dist/agentResponseEvents.js +141 -0
  33. package/dist/apiBasedTools.js +95 -211
  34. package/dist/custom/ChatSurface.vue +31 -21
  35. package/dist/custom/composables/agentStore/constants.ts +8 -1
  36. package/dist/custom/composables/agentStore/useAgentSessions.ts +85 -12
  37. package/dist/custom/composables/useAgentAudio.ts +401 -0
  38. package/dist/custom/composables/useAgentStore.ts +52 -5
  39. package/dist/custom/conversation_area/ConversationArea.vue +1 -1
  40. package/dist/custom/conversation_area/MessageRenderer.vue +12 -1
  41. package/dist/custom/conversation_area/SystemMessageRenderer.vue +28 -0
  42. package/dist/custom/conversation_area/TextRenderer.vue +4 -3
  43. package/dist/custom/conversation_area/ToolRenderer.vue +1 -1
  44. package/dist/custom/package.json +2 -1
  45. package/dist/custom/pnpm-lock.yaml +29 -0
  46. package/dist/custom/public/agentAudio/agent-processing.mp3 +0 -0
  47. package/dist/custom/speech_recognition_frontend/AudioLines.vue +97 -0
  48. package/dist/custom/speech_recognition_frontend/MicrophoneButon.vue +157 -0
  49. package/dist/custom/speech_recognition_frontend/types/voice-activity-detection.d.ts +22 -0
  50. package/dist/custom/speech_recognition_frontend/voiceActivityDetection.ts +151 -0
  51. package/dist/custom/types.ts +52 -2
  52. package/dist/index.js +290 -400
  53. package/index.ts +318 -492
  54. package/package.json +3 -2
  55. package/types.ts +1 -1
@@ -27,12 +27,6 @@ const USER_LANGUAGE_OUTPUT_SCHEMA = {
27
27
  required: ["language", "code"],
28
28
  },
29
29
  };
30
- export function formatLanguagePrompt(language) {
31
- if (!language) {
32
- return "Respond in the user's language.";
33
- }
34
- return `Respond in ${language.language} (${language.code}).`;
35
- }
36
30
  function parseUserLanguage(content) {
37
31
  if (!content) {
38
32
  return null;
@@ -19,8 +19,8 @@ export const contextSchema = z.object({
19
19
  userTimeZone: z.string(),
20
20
  sessionId: z.string(),
21
21
  turnId: z.string(),
22
+ abortSignal: z.custom().optional(),
22
23
  currentPage: z.custom().optional(),
23
- httpExtra: z.custom().optional(),
24
24
  emitToolCallEvent: z.custom(),
25
25
  });
26
26
  function isLangChainAgentCompletionAdapter(adapter) {
@@ -132,7 +132,7 @@ 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, httpExtra, userTimeZone, emitToolCallEvent, sequenceDebugSink, } = params;
135
+ const { name, model, summaryModel, modelMiddleware = [], checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, sessionId, turnId, currentPage, userTimeZone, abortSignal, emitToolCallEvent, sequenceDebugSink, } = params;
136
136
  const tools = yield createAgentTools(customComponentsDir, apiBasedTools);
137
137
  const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
138
138
  const sequenceDebugMiddleware = createSequenceDebugMiddleware(sequenceDebugSink);
@@ -158,6 +158,7 @@ export function callAgent(params) {
158
158
  streamMode: "messages",
159
159
  recursionLimit: 100,
160
160
  callbacks: [createAgentLlmMetricsLogger()],
161
+ signal: abortSignal,
161
162
  configurable: {
162
163
  thread_id: sessionId,
163
164
  },
@@ -166,8 +167,8 @@ export function callAgent(params) {
166
167
  userTimeZone,
167
168
  sessionId,
168
169
  turnId,
170
+ abortSignal,
169
171
  currentPage,
170
- httpExtra,
171
172
  emitToolCallEvent,
172
173
  },
173
174
  });
@@ -8,7 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { listBundledSkillManifests, listProjectSkillManifests, } from "./skills/registry.js";
11
- import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "./tools/index.js";
12
11
  export const DEFAULT_AGENT_SYSTEM_PROMPT = [
13
12
  "You are helpful AI Assistant for Admin Panel.",
14
13
  // about admin
@@ -38,6 +37,30 @@ export function appendCustomSystemPrompt(systemPrompt, customSystemPrompt) {
38
37
  }
39
38
  return `${systemPrompt}\n\n${normalizedCustomSystemPrompt}`;
40
39
  }
40
+ function formatLanguagePrompt(language) {
41
+ if (!language) {
42
+ return "Respond in the user's language.";
43
+ }
44
+ return `Respond in ${language.language} (${language.code}).`;
45
+ }
46
+ function formatAdminUserPrompt(adminUser, usernameField) {
47
+ const adminUserContext = {
48
+ id: adminUser.pk,
49
+ email: adminUser.dbUser[usernameField],
50
+ };
51
+ return [
52
+ "Current admin user context:",
53
+ JSON.stringify(adminUserContext, null, 2),
54
+ "Use this admin user email when the user asks to send information to themselves, the current admin, or the logged-in user.",
55
+ ].join("\n");
56
+ }
57
+ export function buildAgentTurnSystemPrompt(input) {
58
+ return [
59
+ input.agentSystemPrompt,
60
+ formatAdminUserPrompt(input.adminUser, input.usernameField),
61
+ formatLanguagePrompt(input.userLanguage),
62
+ ].join("\n\n");
63
+ }
41
64
  function formatResources(resources) {
42
65
  return resources
43
66
  .map((resource) => `- resourceId: ${resource.resourceId}\n label: ${resource.label}`)
@@ -54,7 +77,6 @@ export function buildAgentSystemPrompt(adminforth_1) {
54
77
  listProjectSkillManifests(adminforth.config.customization.customComponentsDir),
55
78
  listBundledSkillManifests(),
56
79
  ]);
57
- const alwaysAvailableTools = ALWAYS_AVAILABLE_API_TOOL_NAMES.join(", ");
58
80
  const adminBasePath = adminforth.config.baseUrlSlashed;
59
81
  const hiddenResourceIdSet = new Set(hiddenResourceIds);
60
82
  const visibleResources = adminforth.config.resources.filter((resource) => !hiddenResourceIdSet.has(resource.resourceId));
@@ -62,7 +84,6 @@ export function buildAgentSystemPrompt(adminforth_1) {
62
84
  DEFAULT_AGENT_SYSTEM_PROMPT,
63
85
  `ADMIN_BASE_PATH: ${adminBasePath}`,
64
86
  `List of resources:\n${formatResources(visibleResources)}`,
65
- `You have always-available base tools: ${alwaysAvailableTools}.`,
66
87
  primarySkills.length > 0
67
88
  ? `You have primary skills set:\n${formatSkills(primarySkills, "skill_name")}`
68
89
  : "",
@@ -1,6 +1,5 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import YAML from "yaml";
3
- import { serializeUnknownError } from "../apiBasedTools.js";
4
3
  const TOOL_MESSAGE_DEBUG_KEYS = new Set([
5
4
  "metadata",
6
5
  "additional_kwargs",
@@ -29,6 +28,29 @@ function sanitizeToolCallOutputForDebug(output) {
29
28
  }
30
29
  return Object.fromEntries(Object.entries(debugPayload).filter(([key]) => !TOOL_MESSAGE_DEBUG_KEYS.has(key)));
31
30
  }
31
+ function serializeErrorForDebug(error) {
32
+ if (!(error instanceof Error)) {
33
+ return error;
34
+ }
35
+ const errorWithCause = error;
36
+ const serialized = {
37
+ name: error.name,
38
+ message: error.message,
39
+ };
40
+ if (error.stack) {
41
+ serialized.stack = error.stack;
42
+ }
43
+ if (errorWithCause.cause !== undefined) {
44
+ serialized.cause = serializeErrorForDebug(errorWithCause.cause);
45
+ }
46
+ for (const key of Object.getOwnPropertyNames(error)) {
47
+ if (key in serialized) {
48
+ continue;
49
+ }
50
+ serialized[key] = error[key];
51
+ }
52
+ return serialized;
53
+ }
32
54
  export function createToolCallTracker(params) {
33
55
  var _a, _b;
34
56
  const toolCallId = (_a = params.toolCallId) !== null && _a !== void 0 ? _a : randomUUID();
@@ -61,7 +83,7 @@ export function createToolCallTracker(params) {
61
83
  phase: "end",
62
84
  durationMs: Date.now() - startedAt,
63
85
  output: null,
64
- error: YAML.stringify(serializeUnknownError(error)).trimEnd(),
86
+ error: YAML.stringify(serializeErrorForDebug(error)).trimEnd(),
65
87
  });
66
88
  },
67
89
  };
@@ -49,7 +49,7 @@ export function createApiTool(toolName, apiBasedTool) {
49
49
  const normalizedInput = (input !== null && input !== void 0 ? input : {});
50
50
  return apiBasedTool.call({
51
51
  adminUser: runtime.context.adminUser,
52
- httpExtra: runtime.context.httpExtra,
52
+ abortSignal: runtime.context.abortSignal,
53
53
  inputs: normalizedInput,
54
54
  userTimeZone: runtime.context.userTimeZone,
55
55
  });
@@ -0,0 +1,141 @@
1
+ import { randomUUID } from "crypto";
2
+ export function createAgentEventStream(res, options = {}) {
3
+ let isStreamClosed = false;
4
+ let activeBlock = null;
5
+ res.writeHead(200, Object.assign({ "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "Connection": "keep-alive" }, (options.vercelAiUiMessageStream
6
+ ? { "x-vercel-ai-ui-message-stream": "v1" }
7
+ : {})));
8
+ const stream = {
9
+ send(obj) {
10
+ if (isStreamClosed || res.writableEnded || res.destroyed) {
11
+ return;
12
+ }
13
+ res.write(`data: ${JSON.stringify(obj)}\n\n`);
14
+ },
15
+ endActiveBlock() {
16
+ if (!activeBlock) {
17
+ return;
18
+ }
19
+ stream.send({
20
+ type: `${activeBlock.type}-end`,
21
+ id: activeBlock.id,
22
+ });
23
+ activeBlock = null;
24
+ },
25
+ startBlock(type) {
26
+ if ((activeBlock === null || activeBlock === void 0 ? void 0 : activeBlock.type) === type) {
27
+ return activeBlock.id;
28
+ }
29
+ stream.endActiveBlock();
30
+ const id = randomUUID();
31
+ activeBlock = { type, id };
32
+ stream.send({
33
+ type: `${type}-start`,
34
+ id,
35
+ });
36
+ return id;
37
+ },
38
+ start(messageId) {
39
+ stream.send({
40
+ type: "start",
41
+ messageId,
42
+ });
43
+ },
44
+ textDelta(delta) {
45
+ const textId = stream.startBlock("text");
46
+ stream.send({
47
+ type: "text-delta",
48
+ id: textId,
49
+ delta,
50
+ });
51
+ },
52
+ reasoningDelta(delta) {
53
+ const reasoningId = stream.startBlock("reasoning");
54
+ stream.send({
55
+ type: "reasoning-delta",
56
+ id: reasoningId,
57
+ delta,
58
+ });
59
+ },
60
+ toolCall(event) {
61
+ if (options.closeActiveBlockOnToolStart && event.phase === "start") {
62
+ stream.endActiveBlock();
63
+ }
64
+ stream.send({
65
+ type: "data-tool-call",
66
+ data: event,
67
+ });
68
+ },
69
+ transcript(text, language) {
70
+ stream.send({
71
+ type: "transcript",
72
+ data: {
73
+ text,
74
+ language,
75
+ },
76
+ });
77
+ },
78
+ response(text, sessionId, turnId) {
79
+ stream.send({
80
+ type: "response",
81
+ data: {
82
+ text,
83
+ sessionId,
84
+ turnId,
85
+ },
86
+ });
87
+ },
88
+ speechResponse(transcript, response, sessionId, turnId) {
89
+ stream.send({
90
+ type: "speech-response",
91
+ data: {
92
+ transcript,
93
+ response,
94
+ sessionId,
95
+ turnId,
96
+ },
97
+ });
98
+ },
99
+ audioStart(mimeType, format) {
100
+ stream.send({
101
+ type: "audio-start",
102
+ data: {
103
+ mimeType,
104
+ format,
105
+ },
106
+ });
107
+ },
108
+ audioDelta(value) {
109
+ stream.send({
110
+ type: "audio-delta",
111
+ data: {
112
+ base64: Buffer.from(value).toString("base64"),
113
+ },
114
+ });
115
+ },
116
+ audioDone() {
117
+ stream.send({
118
+ type: "audio-done",
119
+ });
120
+ },
121
+ error(error) {
122
+ stream.send({
123
+ type: "error",
124
+ error,
125
+ });
126
+ },
127
+ end() {
128
+ if (isStreamClosed || res.writableEnded || res.destroyed) {
129
+ return;
130
+ }
131
+ stream.endActiveBlock();
132
+ stream.send({
133
+ type: "finish",
134
+ });
135
+ res.write("data: [DONE]\n\n");
136
+ isStreamClosed = true;
137
+ res.end();
138
+ },
139
+ };
140
+ return stream;
141
+ }