@drax/ai-back 3.35.1 → 3.37.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 (50) hide show
  1. package/.env +4 -0
  2. package/dist/agents/ChatbotTaskService.js +143 -0
  3. package/dist/agents/ChatbotTaskTools.js +756 -0
  4. package/dist/agents/DraxAgent.js +4 -7
  5. package/dist/controllers/AIController.js +150 -0
  6. package/dist/controllers/DraxAgentController.js +29 -6
  7. package/dist/factory/DraxAgentFactory.js +15 -0
  8. package/dist/index.js +2 -1
  9. package/dist/interfaces/IAILog.js +1 -0
  10. package/dist/routes/ChatbotTaskRoutes.js +8 -0
  11. package/dist/routes/DraxAgentRoutes.js +2 -1
  12. package/dist/tools/ToolBuilder.js +243 -0
  13. package/dist/vectors/ChromaVector.js +65 -0
  14. package/package.json +3 -3
  15. package/src/agents/DraxAgent.ts +5 -11
  16. package/src/controllers/DraxAgentController.ts +34 -6
  17. package/src/factory/DraxAgentFactory.ts +22 -0
  18. package/src/index.ts +2 -0
  19. package/src/interfaces/IDraxAgent.ts +2 -0
  20. package/src/interfaces/IDraxAgentController.ts +2 -0
  21. package/src/routes/DraxAgentRoutes.ts +2 -1
  22. package/test/DraxAgent.test.ts +26 -5
  23. package/tsconfig.tsbuildinfo +1 -1
  24. package/types/agents/ChatbotTaskService.d.ts +42 -0
  25. package/types/agents/ChatbotTaskService.d.ts.map +1 -0
  26. package/types/agents/ChatbotTaskTools.d.ts +54 -0
  27. package/types/agents/ChatbotTaskTools.d.ts.map +1 -0
  28. package/types/agents/DraxAgent.d.ts +3 -3
  29. package/types/agents/DraxAgent.d.ts.map +1 -1
  30. package/types/controllers/AIController.d.ts +25 -0
  31. package/types/controllers/AIController.d.ts.map +1 -0
  32. package/types/controllers/DraxAgentController.d.ts +6 -2
  33. package/types/controllers/DraxAgentController.d.ts.map +1 -1
  34. package/types/factory/DraxAgentFactory.d.ts +9 -0
  35. package/types/factory/DraxAgentFactory.d.ts.map +1 -0
  36. package/types/index.d.ts +3 -2
  37. package/types/index.d.ts.map +1 -1
  38. package/types/interfaces/IAILog.d.ts +77 -0
  39. package/types/interfaces/IAILog.d.ts.map +1 -0
  40. package/types/interfaces/IDraxAgent.d.ts +2 -0
  41. package/types/interfaces/IDraxAgent.d.ts.map +1 -1
  42. package/types/interfaces/IDraxAgentController.d.ts +2 -0
  43. package/types/interfaces/IDraxAgentController.d.ts.map +1 -1
  44. package/types/routes/ChatbotTaskRoutes.d.ts +4 -0
  45. package/types/routes/ChatbotTaskRoutes.d.ts.map +1 -0
  46. package/types/routes/DraxAgentRoutes.d.ts.map +1 -1
  47. package/types/tools/ToolBuilder.d.ts +47 -0
  48. package/types/tools/ToolBuilder.d.ts.map +1 -0
  49. package/types/vectors/ChromaVector.d.ts +21 -0
  50. package/types/vectors/ChromaVector.d.ts.map +1 -0
@@ -19,22 +19,15 @@ import AgentSessionServiceFactory from "../factory/services/AgentSessionServiceF
19
19
  import type {AgentSessionService} from "../services/AgentSessionService.js";
20
20
 
21
21
  class DraxAgent {
22
- private static singleton?: DraxAgent;
23
-
24
22
  protected sessions: Map<string, DraxAgentSession> = new Map();
25
23
  protected config: DraxAgentConfig = {
26
24
  systemPrompt: "Sos un asistente del sistema. Responde de forma clara, breve y util.",
27
25
  };
28
26
 
29
- private constructor() {
30
- }
31
-
32
- static instance(): DraxAgent {
33
- if (!DraxAgent.singleton) {
34
- DraxAgent.singleton = new DraxAgent();
35
- }
36
-
37
- return DraxAgent.singleton;
27
+ constructor(
28
+ public readonly identifier: string = "default",
29
+ public readonly description: string = "",
30
+ ) {
38
31
  }
39
32
 
40
33
  configure(config: DraxAgentConfig): this {
@@ -132,6 +125,7 @@ class DraxAgent {
132
125
  });
133
126
 
134
127
  return {
128
+ agentIdentifier: this.identifier,
135
129
  sessionId: session.id,
136
130
  message: assistantMessage,
137
131
  navigationPath: navigationState.path,
@@ -1,7 +1,9 @@
1
1
  import {z} from "zod";
2
2
  import {CommonController} from "@drax/common-back";
3
3
  import {DraxAgent} from "../agents/DraxAgent.js";
4
+ import DraxAgentFactory from "../factory/DraxAgentFactory.js";
4
5
  import {AgentPermissions} from "../permissions/AgentPermissions.js";
6
+ import type {DraxAgentControllerOptions} from "../interfaces/IDraxAgentController.js";
5
7
 
6
8
  const PromptImageSchema = z.object({
7
9
  url: z.string().min(1),
@@ -34,6 +36,7 @@ const PromptInputFileSchema = z.object({
34
36
  });
35
37
 
36
38
  const AgentSessionRequestSchema = z.object({
39
+ identifier: z.string().min(1).optional(),
37
40
  sessionId: z.string().optional(),
38
41
  userId: z.string().optional().nullable(),
39
42
  tenantId: z.string().optional().nullable(),
@@ -55,13 +58,31 @@ const AgentMessageRequestSchema = AgentSessionRequestSchema.extend({
55
58
  });
56
59
 
57
60
  class DraxAgentController extends CommonController {
58
- protected agent: DraxAgent;
59
61
  protected permission: string | false;
62
+ protected defaultAgentIdentifier: string;
63
+ protected defaultAgentDescription: string;
60
64
 
61
- constructor() {
65
+ constructor(options: DraxAgentControllerOptions = {}) {
62
66
  super();
63
- this.permission = AgentPermissions.Session;
64
- this.agent = DraxAgent.instance();
67
+ this.permission = options.permission ?? AgentPermissions.Session;
68
+ this.defaultAgentIdentifier = options.agentIdentifier ?? "default";
69
+ this.defaultAgentDescription = options.agentDescription ?? "";
70
+ DraxAgentFactory.instance(this.defaultAgentIdentifier, this.defaultAgentDescription);
71
+ }
72
+
73
+ async agents(request, reply) {
74
+ try {
75
+ this.assertAccess(request);
76
+
77
+ return reply.send({
78
+ agents: DraxAgentFactory.agents().map(agent => ({
79
+ identifier: agent.identifier,
80
+ description: agent.description,
81
+ })),
82
+ });
83
+ } catch (e: any) {
84
+ this.handleControllerError(e, reply);
85
+ }
65
86
  }
66
87
 
67
88
  async startSession(request, reply) {
@@ -69,13 +90,15 @@ class DraxAgentController extends CommonController {
69
90
  this.assertAccess(request);
70
91
 
71
92
  const input = AgentSessionRequestSchema.parse(request.body ?? {});
72
- const session = await this.agent.startSession({
93
+ const agent = this.resolveAgent(input.identifier);
94
+ const session = await agent.startSession({
73
95
  sessionId: input.sessionId,
74
96
  userId: this.resolveUserId(request, input.userId),
75
97
  tenantId: this.resolveTenantId(request, input.tenantId),
76
98
  });
77
99
 
78
100
  return reply.send({
101
+ agentIdentifier: agent.identifier,
79
102
  sessionId: session.id,
80
103
  createdAt: session.createdAt,
81
104
  updatedAt: session.updatedAt,
@@ -90,7 +113,8 @@ class DraxAgentController extends CommonController {
90
113
  this.assertAccess(request);
91
114
 
92
115
  const input = AgentMessageRequestSchema.parse(request.body ?? {});
93
- const response = await this.agent.sendMessage({
116
+ const agent = this.resolveAgent(input.identifier);
117
+ const response = await agent.sendMessage({
94
118
  ...input,
95
119
  userId: this.resolveUserId(request, input.userId),
96
120
  tenantId: this.resolveTenantId(request, input.tenantId),
@@ -104,6 +128,10 @@ class DraxAgentController extends CommonController {
104
128
  }
105
129
  }
106
130
 
131
+ protected resolveAgent(identifier?: string): DraxAgent {
132
+ return DraxAgentFactory.instance(identifier ?? this.defaultAgentIdentifier);
133
+ }
134
+
107
135
  protected assertAccess(request: any) {
108
136
  if (this.permission === false) {
109
137
  return;
@@ -0,0 +1,22 @@
1
+ import DraxAgent from "../agents/DraxAgent.js";
2
+
3
+ class DraxAgentFactory {
4
+ private static singletons: Record<string, DraxAgent> = {};
5
+
6
+ public static instance(identifier: string = "default", description: string = ""): DraxAgent {
7
+ if (!DraxAgentFactory.singletons[identifier]) {
8
+ DraxAgentFactory.singletons[identifier] = new DraxAgent(identifier, description);
9
+ }
10
+
11
+ return DraxAgentFactory.singletons[identifier];
12
+ }
13
+
14
+ public static agents(): DraxAgent[] {
15
+ return Object.values(DraxAgentFactory.singletons);
16
+ }
17
+ }
18
+
19
+ export default DraxAgentFactory;
20
+ export {
21
+ DraxAgentFactory,
22
+ };
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {OpenAiProviderFactory} from "./factory/OpenAiProviderFactory.js";
9
9
  import {GoogleAiProviderFactory} from "./factory/GoogleAiProviderFactory.js";
10
10
  import {OllamaAiProviderFactory} from "./factory/OllamaAiProviderFactory.js";
11
11
  import {AiProviderFactory} from "./factory/AiProviderFactory.js";
12
+ import {DraxAgentFactory} from "./factory/DraxAgentFactory.js";
12
13
  import AILogServiceFactory from "./factory/services/AILogServiceFactory.js";
13
14
  import {OpenAiProvider} from "./providers/OpenAiProvider.js";
14
15
  import {GoogleAiProvider} from "./providers/GoogleAiProvider.js";
@@ -112,6 +113,7 @@ export {
112
113
  GoogleAiProviderFactory,
113
114
  OllamaAiProviderFactory,
114
115
  AiProviderFactory,
116
+ DraxAgentFactory,
115
117
  AILogServiceFactory,
116
118
  OpenAiProvider,
117
119
  GoogleAiProvider,
@@ -40,6 +40,7 @@ interface DraxAgentConfig {
40
40
  }
41
41
 
42
42
  interface DraxAgentSessionInput {
43
+ identifier?: string;
43
44
  sessionId?: string;
44
45
  userId?: string | null;
45
46
  tenantId?: string | null;
@@ -69,6 +70,7 @@ interface DraxAgentMessageInput extends DraxAgentSessionInput {
69
70
  }
70
71
 
71
72
  interface DraxAgentMessageOutput {
73
+ agentIdentifier: string;
72
74
  sessionId: string;
73
75
  message: string;
74
76
  navigationPath?: string | null;
@@ -1,5 +1,7 @@
1
1
  interface DraxAgentControllerOptions {
2
2
  permission?: string | false;
3
+ agentIdentifier?: string;
4
+ agentDescription?: string;
3
5
  }
4
6
 
5
7
  export type {DraxAgentControllerOptions};
@@ -1,9 +1,10 @@
1
1
  import DraxAgentController from "../controllers/DraxAgentController.js";
2
2
 
3
3
  async function DraxAgentRoutes(fastify, options:any) {
4
- const controller = new DraxAgentController();
4
+ const controller = new DraxAgentController(options);
5
5
  const prefix = "/api/ai/agent";
6
6
 
7
+ fastify.get(`${prefix}`, (req, rep) => controller.agents(req, rep));
7
8
  fastify.post(`${prefix}/session`, (req, rep) => controller.startSession(req, rep));
8
9
  fastify.post(`${prefix}/message`, (req, rep) => controller.message(req, rep));
9
10
  }
@@ -1,5 +1,6 @@
1
1
  import {describe, expect, test} from "vitest";
2
2
  import {DraxAgent} from "../src/agents/DraxAgent.js";
3
+ import {DraxAgentFactory} from "../src/factory/DraxAgentFactory.js";
3
4
  import type {IAIProvider, IPromptParams, IPromptResponse, IPromptTool} from "../src/interfaces/IAIProvider.js";
4
5
 
5
6
  class MockProvider implements IAIProvider {
@@ -23,9 +24,29 @@ class MockProvider implements IAIProvider {
23
24
  }
24
25
 
25
26
  describe("DraxAgent", () => {
27
+ test("factory returns one agent instance per identifier", () => {
28
+ expect(DraxAgentFactory.instance()).toBe(DraxAgentFactory.instance("default"));
29
+ expect(DraxAgentFactory.instance("taskSpecialist")).toBe(DraxAgentFactory.instance("taskSpecialist"));
30
+ expect(DraxAgentFactory.instance("taskSpecialist")).not.toBe(DraxAgentFactory.instance("default"));
31
+ expect(DraxAgentFactory.agents()).toContain(DraxAgentFactory.instance("taskSpecialist"));
32
+ expect(new DraxAgent()).not.toBe(new DraxAgent());
33
+ });
34
+
35
+ test("stores agent identifier and description", () => {
36
+ const defaultAgent = new DraxAgent();
37
+ const specialist = DraxAgentFactory.instance("taskSpecialistWithDescription", "Resuelve tareas especificas");
38
+
39
+ expect(defaultAgent.identifier).toBe("default");
40
+ expect(defaultAgent.description).toBe("");
41
+ expect(specialist.identifier).toBe("taskSpecialistWithDescription");
42
+ expect(specialist.description).toBe("Resuelve tareas especificas");
43
+ expect(DraxAgentFactory.instance("taskSpecialistWithDescription", "Otra descripcion")).toBe(specialist);
44
+ expect(DraxAgentFactory.instance("taskSpecialistWithDescription").description).toBe("Resuelve tareas especificas");
45
+ });
46
+
26
47
  test("creates a session and sends messages through the injected provider", async () => {
27
48
  const provider = new MockProvider();
28
- const agent = DraxAgent.instance().clearSessions().configure({
49
+ const agent = new DraxAgent().configure({
29
50
  provider,
30
51
  systemPrompt: "Sos un asistente.",
31
52
  sessionService: false,
@@ -74,7 +95,7 @@ describe("DraxAgent", () => {
74
95
  },
75
96
  };
76
97
 
77
- const agent = DraxAgent.instance().clearSessions().configure({
98
+ const agent = new DraxAgent().configure({
78
99
  provider,
79
100
  systemPrompt: "Prompt base.",
80
101
  sessionService: false,
@@ -99,7 +120,7 @@ describe("DraxAgent", () => {
99
120
 
100
121
  test("uses previous session messages as history", async () => {
101
122
  const provider = new MockProvider();
102
- const agent = DraxAgent.instance().clearSessions().configure({
123
+ const agent = new DraxAgent().configure({
103
124
  provider,
104
125
  systemPrompt: "Sos un asistente.",
105
126
  sessionService: false,
@@ -125,7 +146,7 @@ describe("DraxAgent", () => {
125
146
 
126
147
  test("returns a navigation path from tool execution metadata", async () => {
127
148
  const provider = new MockProvider();
128
- const agent = DraxAgent.instance().clearSessions().configure({
149
+ const agent = new DraxAgent().configure({
129
150
  provider,
130
151
  systemPrompt: "Sos un asistente.",
131
152
  sessionService: false,
@@ -178,7 +199,7 @@ describe("DraxAgent", () => {
178
199
  }),
179
200
  } as any;
180
201
 
181
- const agent = DraxAgent.instance().clearSessions().configure({
202
+ const agent = new DraxAgent().configure({
182
203
  provider,
183
204
  systemPrompt: "Sos un asistente.",
184
205
  sessionService,