@adminforth/agent 1.49.3 → 1.50.1

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 (41) hide show
  1. package/agent/middleware/sequenceDebug.ts +42 -7
  2. package/agent/simpleAgent.ts +15 -0
  3. package/agent/systemPrompt.ts +6 -1
  4. package/agent/tools/index.ts +2 -0
  5. package/agent/tools/navigateUser.ts +210 -0
  6. package/agentEvents.ts +4 -0
  7. package/agentTurnService.ts +14 -0
  8. package/build.log +2 -2
  9. package/chatSurfaceService.ts +7 -0
  10. package/custom/composables/agentStore/useAgentChat.ts +8 -1
  11. package/custom/composables/useAgentAudio.ts +5 -0
  12. package/custom/composables/useAgentStore.ts +43 -0
  13. package/custom/skills/fetch_data/SKILL.md +2 -0
  14. package/custom/skills/mutate_data/SKILL.md +4 -0
  15. package/custom/tsconfig.json +0 -1
  16. package/custom/types.ts +6 -0
  17. package/dist/agent/middleware/sequenceDebug.d.ts +6 -0
  18. package/dist/agent/middleware/sequenceDebug.js +33 -6
  19. package/dist/agent/simpleAgent.d.ts +8 -0
  20. package/dist/agent/simpleAgent.js +9 -1
  21. package/dist/agent/systemPrompt.d.ts +1 -0
  22. package/dist/agent/systemPrompt.js +5 -1
  23. package/dist/agent/tools/index.js +2 -0
  24. package/dist/agent/tools/navigateUser.d.ts +55 -0
  25. package/dist/agent/tools/navigateUser.js +163 -0
  26. package/dist/agentEvents.d.ts +3 -0
  27. package/dist/agentTurnService.d.ts +2 -0
  28. package/dist/agentTurnService.js +10 -0
  29. package/dist/chatSurfaceService.js +10 -3
  30. package/dist/custom/composables/agentStore/useAgentChat.ts +8 -1
  31. package/dist/custom/composables/useAgentAudio.ts +5 -0
  32. package/dist/custom/composables/useAgentStore.ts +43 -0
  33. package/dist/custom/skills/fetch_data/SKILL.md +2 -0
  34. package/dist/custom/skills/mutate_data/SKILL.md +4 -0
  35. package/dist/custom/tsconfig.json +0 -1
  36. package/dist/custom/types.ts +6 -0
  37. package/dist/endpoints/chatSurfaces.js +20 -0
  38. package/dist/surfaces/web-sse/createSseEventEmitter.js +11 -0
  39. package/endpoints/chatSurfaces.ts +29 -0
  40. package/package.json +1 -1
  41. package/surfaces/web-sse/createSseEventEmitter.ts +12 -0
@@ -1,6 +1,7 @@
1
1
  import { defineStore } from 'pinia';
2
2
  import { IAgentSession, ISessionsListItem } from '../types';
3
3
  import { ref, nextTick, computed, watch, onMounted } from 'vue';
4
+ import { useRouter } from 'vue-router';
4
5
  import { useAdminforth } from '@/adminforth';
5
6
  import { useCoreStore } from '@/stores/core';
6
7
  import { useAgentTransitions } from './useAgentTransitions';
@@ -28,6 +29,7 @@ export const useAgentStore = defineStore('agent', () => {
28
29
  const adminforth = useAdminforth();
29
30
  const isChatOpen = ref(false);
30
31
  const isSessionHistoryOpen = ref(false);
32
+ const router = useRouter();
31
33
  const textInput = ref<HTMLTextAreaElement | null>(null);
32
34
  const userMessageInput = ref();
33
35
  const trimmedUserMessage = computed(() => userMessageInput.value ? userMessageInput.value.trim() : '');
@@ -54,6 +56,7 @@ export const useAgentStore = defineStore('agent', () => {
54
56
  } = createAgentChatManager({
55
57
  lastMessage,
56
58
  activeModeName,
59
+ onOpenPage: openAgentPage,
57
60
  });
58
61
  const {
59
62
  userMessagePlaceholder,
@@ -324,6 +327,45 @@ export const useAgentStore = defineStore('agent', () => {
324
327
  addSystemMessage(RESERVED_SYSTEM_MESSAGE_CONTENT.AGENT_RESPONSE_ABORTED);
325
328
  }
326
329
 
330
+ function resolveInternalRoute(href: string): string | null {
331
+ if (href.startsWith('#')) {
332
+ return `${window.location.pathname}${window.location.search}${href}`;
333
+ }
334
+
335
+ if (href.startsWith('//')) {
336
+ return null;
337
+ }
338
+
339
+ const isAbsoluteWithScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href);
340
+ const baseUrl = isAbsoluteWithScheme
341
+ ? undefined
342
+ : `${window.location.origin}/`;
343
+ const resolvedUrl = new URL(href, baseUrl ?? window.location.href);
344
+
345
+ if (resolvedUrl.origin !== window.location.origin) {
346
+ return null;
347
+ }
348
+
349
+ return `${resolvedUrl.pathname}${resolvedUrl.search}${resolvedUrl.hash}`;
350
+ }
351
+
352
+ function openAgentPage(targetPath: string) {
353
+ const internalRoute = resolveInternalRoute(targetPath);
354
+
355
+ if (internalRoute === null) {
356
+ console.warn('Ignoring external agent navigation target:', targetPath);
357
+ return;
358
+ }
359
+
360
+ if (isFullScreen.value && !coreStore.isMobile) {
361
+ setFullScreen(false);
362
+ } else if (coreStore.isMobile) {
363
+ setIsChatOpen(false);
364
+ }
365
+
366
+ void router.push(internalRoute);
367
+ }
368
+
327
369
  return {
328
370
  //_________-Sessions management-_____________
329
371
  activeSessionId,
@@ -374,6 +416,7 @@ export const useAgentStore = defineStore('agent', () => {
374
416
  addAgentMessage,
375
417
  addUserMessage,
376
418
  addDataToolCallMessage,
419
+ openAgentPage,
377
420
  setCurrentChatStatus,
378
421
  updateLastAgentMessage
379
422
  }
@@ -24,6 +24,8 @@ If several rows look similar, do not guess which one is "the same" record. Show
24
24
 
25
25
  For long texts show only several first words and add "..." at the end (only if user did not request this field specifically).
26
26
 
27
+ Never show information about more than 10 records in one message. If a tool returns more than 10 relevant records, summarize the total count if known, show only the 10 most relevant records, and offer to narrow filters, sort differently, or continue with the next 10.
28
+
27
29
  Also when you communicate with user about record, add related link to this record. Build it as `{ADMIN_BASE_PATH}resource/{resourceId}/show/{primary key}`. Use _label from `get_resource_data` as anchor text for link (use markdown link). Links should always be relative paths and must start with `ADMIN_BASE_PATH`. Do not add an extra slash after `ADMIN_BASE_PATH`.
28
30
 
29
31
  Before sending the link, verify that the `resourceId`, `{primary key}`, `_label`, and shown fields come from the same exact returned row.
@@ -27,6 +27,8 @@ Also please add related link to record with will be changed. Build it as `{ADMIN
27
27
 
28
28
  Before sending the confirmation, verify that the `resourceId`, `{primary key}`, `_label`, and all shown fields come from the same exact fetched row.
29
29
 
30
+ Never show information about more than 10 records in one message. If a mutation plan affects more than 10 records, show only the 10 most important examples plus the total count if known, and ask the user to confirm the clearly described full batch.
31
+
30
32
  And in the same message ask user for final confirmation.
31
33
 
32
34
  When creating new record, show user all data which you gona create and in same message ask for confirmation.
@@ -123,6 +125,8 @@ For decimal fields please use string values with dot as decimal separator.
123
125
 
124
126
  After creation of new record also show user a link to this record. If several records record were created, show links to all of them in list.
125
127
 
128
+ If more than 10 records were created, show links or details for only 10 of them and summarize the remaining count.
129
+
126
130
  Omit any pictures or file paths, you are not capable of doing it. If they are not required all is good, if they are required, explain to user that you are not able to create record because of this reason.
127
131
 
128
132
  ### Working with dates
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "baseUrl": ".", // This should point to your project root
4
3
  "paths": {
5
4
  "@/*": [
6
5
  "../node_modules/adminforth/dist/spa/src/*"
@@ -93,6 +93,12 @@ export type SpeechStreamEvent =
93
93
  type: 'data-tool-call';
94
94
  data: any;
95
95
  }
96
+ | {
97
+ type: 'open-page';
98
+ data: {
99
+ targetPath: string;
100
+ };
101
+ }
96
102
  | {
97
103
  type: 'finish';
98
104
  };
@@ -7,6 +7,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ function getHeaderValue(headers, name) {
11
+ var _a;
12
+ const value = (_a = headers[name]) !== null && _a !== void 0 ? _a : headers[name.toLowerCase()];
13
+ if (Array.isArray(value)) {
14
+ return value[0];
15
+ }
16
+ return typeof value === "string" ? value : undefined;
17
+ }
18
+ function getRequestOrigin(input) {
19
+ var _a, _b, _c, _d;
20
+ const forwardedProto = (_b = (_a = getHeaderValue(input.headers, "x-forwarded-proto")) === null || _a === void 0 ? void 0 : _a.split(",")[0]) === null || _b === void 0 ? void 0 : _b.trim();
21
+ const forwardedHost = (_d = (_c = getHeaderValue(input.headers, "x-forwarded-host")) === null || _c === void 0 ? void 0 : _c.split(",")[0]) === null || _d === void 0 ? void 0 : _d.trim();
22
+ const host = forwardedHost !== null && forwardedHost !== void 0 ? forwardedHost : getHeaderValue(input.headers, "host");
23
+ if (!host) {
24
+ return undefined;
25
+ }
26
+ const proto = forwardedProto !== null && forwardedProto !== void 0 ? forwardedProto : (host.startsWith("localhost") || host.startsWith("127.0.0.1") ? "http" : "https");
27
+ return `${proto}://${host}`;
28
+ }
10
29
  export function setupChatSurfaceEndpoints(ctx, server) {
11
30
  var _a;
12
31
  for (const adapter of (_a = ctx.options.chatSurfaceAdapters) !== null && _a !== void 0 ? _a : []) {
@@ -26,6 +45,7 @@ export function setupChatSurfaceEndpoints(ctx, server) {
26
45
  const incoming = yield adapter.parseIncomingMessage(surfaceContext);
27
46
  if (!incoming)
28
47
  return { ok: true };
48
+ incoming.metadata = Object.assign(Object.assign({}, incoming.metadata), { adminPublicOrigin: getRequestOrigin(endpointInput) });
29
49
  const sink = yield adapter.createEventSink(surfaceContext, incoming);
30
50
  try {
31
51
  yield ctx.handleChatSurfaceMessage(adapter, incoming, sink);
@@ -88,6 +88,14 @@ function createAgentEventStream(res, options = {}) {
88
88
  },
89
89
  });
90
90
  },
91
+ openPage(targetPath) {
92
+ stream.send({
93
+ type: isAiUiMessageStream ? "data-open-page" : "open-page",
94
+ data: {
95
+ targetPath,
96
+ },
97
+ });
98
+ },
91
99
  transcript(text, language) {
92
100
  stream.send({
93
101
  type: isAiUiMessageStream ? "data-transcript" : "transcript",
@@ -186,6 +194,9 @@ export function createSseEventEmitter(res, options = {}) {
186
194
  case "rendering":
187
195
  stream.rendering(event.phase, event.label);
188
196
  break;
197
+ case "open-page":
198
+ stream.openPage(event.targetPath);
199
+ break;
189
200
  case "transcript":
190
201
  stream.transcript(event.text, event.language);
191
202
  break;
@@ -4,6 +4,31 @@ import type {
4
4
  } from "adminforth";
5
5
  import type { ChatSurfaceEndpointsContext } from "./context.js";
6
6
 
7
+ function getHeaderValue(headers: Record<string, unknown>, name: string) {
8
+ const value = headers[name] ?? headers[name.toLowerCase()];
9
+
10
+ if (Array.isArray(value)) {
11
+ return value[0];
12
+ }
13
+
14
+ return typeof value === "string" ? value : undefined;
15
+ }
16
+
17
+ function getRequestOrigin(input: IAdminForthEndpointHandlerInput) {
18
+ const forwardedProto = getHeaderValue(input.headers, "x-forwarded-proto")?.split(",")[0]?.trim();
19
+ const forwardedHost = getHeaderValue(input.headers, "x-forwarded-host")?.split(",")[0]?.trim();
20
+ const host = forwardedHost ?? getHeaderValue(input.headers, "host");
21
+
22
+ if (!host) {
23
+ return undefined;
24
+ }
25
+
26
+ const proto = forwardedProto
27
+ ?? (host.startsWith("localhost") || host.startsWith("127.0.0.1") ? "http" : "https");
28
+
29
+ return `${proto}://${host}`;
30
+ }
31
+
7
32
  export function setupChatSurfaceEndpoints(ctx: ChatSurfaceEndpointsContext, server: IHttpServer) {
8
33
  for (const adapter of ctx.options.chatSurfaceAdapters ?? []) {
9
34
  server.endpoint({
@@ -21,6 +46,10 @@ export function setupChatSurfaceEndpoints(ctx: ChatSurfaceEndpointsContext, serv
21
46
 
22
47
  const incoming = await adapter.parseIncomingMessage(surfaceContext);
23
48
  if (!incoming) return { ok: true };
49
+ incoming.metadata = {
50
+ ...incoming.metadata,
51
+ adminPublicOrigin: getRequestOrigin(endpointInput),
52
+ };
24
53
 
25
54
  const sink = await adapter.createEventSink(surfaceContext, incoming);
26
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.49.3",
3
+ "version": "1.50.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -123,6 +123,15 @@ function createAgentEventStream(
123
123
  });
124
124
  },
125
125
 
126
+ openPage(targetPath: string) {
127
+ stream.send({
128
+ type: isAiUiMessageStream ? "data-open-page" : "open-page",
129
+ data: {
130
+ targetPath,
131
+ },
132
+ });
133
+ },
134
+
126
135
  transcript(text: string, language?: string) {
127
136
  stream.send({
128
137
  type: isAiUiMessageStream ? "data-transcript" : "transcript",
@@ -250,6 +259,9 @@ export function createSseEventEmitter(
250
259
  case "rendering":
251
260
  stream.rendering(event.phase, event.label);
252
261
  break;
262
+ case "open-page":
263
+ stream.openPage(event.targetPath);
264
+ break;
253
265
  case "transcript":
254
266
  stream.transcript(event.text, event.language);
255
267
  break;