@drax/ai-back 3.43.0 → 3.44.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.
package/dist/index.js CHANGED
@@ -44,7 +44,8 @@ import TTSRoutes from "./routes/TTSRoutes.js";
44
44
  import DraxAgentRoutes from "./routes/DraxAgentRoutes.js";
45
45
  import AgentSessionRoutes from "./routes/AgentSessionRoutes.js";
46
46
  import { DraxAgent } from "./agents/DraxAgent.js";
47
- export { OpenAiConfig, GoogleAiConfig, OllamaAiConfig, DeepSeekConfig, ElevenLabsTTSConfig, AILogSchema, AILogBaseSchema, TTSRequestSchema, TTSVoiceSettingsSchema, AILogModel, AILogMongoRepository, AILogSqliteRepository, OpenAiProviderFactory, GoogleAiProviderFactory, OllamaAiProviderFactory, DeepSeekAiProviderFactory, AiProviderFactory, ElevenLabsTTSProviderFactory, TTSProviderFactory, DraxAgentFactory, AILogServiceFactory, OpenAiProvider, GoogleAiProvider, OllamaAiProvider, DeepSeekAiProvider, ElevenLabsTTSProvider, BuilderTool,
47
+ import { BuildContextTool } from "./tools/BuildContextTool.js";
48
+ export { OpenAiConfig, GoogleAiConfig, OllamaAiConfig, DeepSeekConfig, ElevenLabsTTSConfig, AILogSchema, AILogBaseSchema, TTSRequestSchema, TTSVoiceSettingsSchema, AILogModel, AILogMongoRepository, AILogSqliteRepository, OpenAiProviderFactory, GoogleAiProviderFactory, OllamaAiProviderFactory, DeepSeekAiProviderFactory, AiProviderFactory, ElevenLabsTTSProviderFactory, TTSProviderFactory, DraxAgentFactory, AILogServiceFactory, OpenAiProvider, GoogleAiProvider, OllamaAiProvider, DeepSeekAiProvider, ElevenLabsTTSProvider, BuilderTool, BuildContextTool,
48
49
  //Service
49
50
  KnowledgeService, AILogService, TTSGenericService, PromptAudioService,
50
51
  //Permissions
@@ -0,0 +1,267 @@
1
+ import { setNestedValue, UnauthorizedError } from "@drax/common-back";
2
+ import { BuilderTool } from "./BuilderTool.js";
3
+ class BuildContextTool extends BuilderTool {
4
+ constructor(options) {
5
+ super({
6
+ ...options,
7
+ service: BuildContextTool.createContextService(options),
8
+ });
9
+ }
10
+ static fromPromptContext(options, promptContext) {
11
+ return new BuildContextTool({
12
+ ...options,
13
+ context: {
14
+ userId: promptContext.input?.userId ?? promptContext.session.userId ?? null,
15
+ tenantId: promptContext.input?.tenantId ?? promptContext.session.tenantId ?? null,
16
+ },
17
+ });
18
+ }
19
+ static createContextService(options) {
20
+ const service = options.service;
21
+ const helper = new BuildContextToolServiceHelper(options);
22
+ const contextService = { ...service };
23
+ if (typeof service.create === "function") {
24
+ contextService.create = async (data) => service.create?.(helper.applySetters(helper.clonePayload(data)));
25
+ }
26
+ if (typeof service.update === "function") {
27
+ contextService.update = async (id, data) => {
28
+ const preItem = await service.findById?.(id);
29
+ helper.assertWritable(preItem, "update");
30
+ const payload = helper.removeSetterFields(helper.clonePayload(data));
31
+ return service.update?.(id, payload);
32
+ };
33
+ }
34
+ if (typeof service.updatePartial === "function") {
35
+ contextService.updatePartial = async (id, data) => {
36
+ const preItem = await service.findById?.(id);
37
+ helper.assertWritable(preItem, "update");
38
+ const payload = helper.removeSetterFields(helper.clonePayload(data));
39
+ return service.updatePartial?.(id, payload);
40
+ };
41
+ }
42
+ if (typeof service.delete === "function") {
43
+ contextService.delete = async (id) => {
44
+ const item = await service.findById?.(id);
45
+ helper.assertWritable(item, "delete");
46
+ return service.delete?.(id);
47
+ };
48
+ }
49
+ if (typeof service.findById === "function") {
50
+ contextService.findById = async (id) => {
51
+ const item = await service.findById?.(id);
52
+ helper.assertReadable(item);
53
+ return item;
54
+ };
55
+ }
56
+ if (typeof service.findByIds === "function") {
57
+ contextService.findByIds = async (ids) => {
58
+ const items = await service.findByIds?.(ids);
59
+ helper.assertReadableItems(items);
60
+ return items;
61
+ };
62
+ }
63
+ if (typeof service.findOneBy === "function") {
64
+ contextService.findOneBy = async (field, value, filters = []) => service.findOneBy?.(field, value, helper.applyReadFilters(filters));
65
+ }
66
+ if (typeof service.findOne === "function") {
67
+ contextService.findOne = async (findOptions) => service.findOne?.({
68
+ ...findOptions,
69
+ filters: helper.applyReadFilters(findOptions?.filters ?? []),
70
+ });
71
+ }
72
+ if (typeof service.findBy === "function") {
73
+ contextService.findBy = async (field, value, limit = helper.defaultLimit, filters = []) => service.findBy?.(field, value, limit, helper.applyReadFilters(filters));
74
+ }
75
+ if (typeof service.fetchAll === "function") {
76
+ contextService.fetchAll = async () => {
77
+ const filters = helper.applyReadFilters([]);
78
+ if (filters.length > 0 && typeof service.find === "function") {
79
+ return service.find({
80
+ search: "",
81
+ filters,
82
+ order: false,
83
+ orderBy: "",
84
+ limit: helper.defaultLimit,
85
+ });
86
+ }
87
+ return service.fetchAll?.();
88
+ };
89
+ }
90
+ if (typeof service.findFirst === "function") {
91
+ contextService.findFirst = async (quantity, filters = []) => service.findFirst?.(quantity, helper.applyReadFilters(filters));
92
+ }
93
+ if (typeof service.findLast === "function") {
94
+ contextService.findLast = async (quantity, filters = []) => service.findLast?.(quantity, helper.applyReadFilters(filters));
95
+ }
96
+ if (typeof service.search === "function") {
97
+ contextService.search = async (value, limit = helper.defaultLimit, filters = []) => service.search?.(value, limit, helper.applyReadFilters(filters));
98
+ }
99
+ if (typeof service.find === "function") {
100
+ contextService.find = async (findOptions) => service.find?.({
101
+ ...findOptions,
102
+ filters: helper.applyReadFilters(findOptions?.filters ?? []),
103
+ });
104
+ }
105
+ if (typeof service.paginate === "function") {
106
+ contextService.paginate = async (paginateOptions) => service.paginate?.({
107
+ ...paginateOptions,
108
+ filters: helper.applyReadFilters(paginateOptions?.filters ?? []),
109
+ });
110
+ }
111
+ if (typeof service.groupBy === "function") {
112
+ contextService.groupBy = async (groupByOptions) => service.groupBy?.({
113
+ ...groupByOptions,
114
+ filters: helper.applyReadFilters(groupByOptions?.filters ?? []),
115
+ });
116
+ }
117
+ return contextService;
118
+ }
119
+ }
120
+ class BuildContextToolServiceHelper {
121
+ constructor(options) {
122
+ this.context = options.context ?? {};
123
+ this.permission = options.permission;
124
+ this.tenantField = options.tenantField ?? "tenant";
125
+ this.userField = options.userField ?? "user";
126
+ this.tenantFilter = options.tenantFilter ?? false;
127
+ this.tenantSetter = options.tenantSetter ?? false;
128
+ this.tenantAssert = options.tenantAssert ?? false;
129
+ this.userFilter = options.userFilter ?? false;
130
+ this.userSetter = options.userSetter ?? false;
131
+ this.userAssert = options.userAssert ?? false;
132
+ this.defaultLimit = options.defaultLimit ?? 1000;
133
+ }
134
+ clonePayload(payload) {
135
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
136
+ return payload;
137
+ }
138
+ return { ...payload };
139
+ }
140
+ applySetters(payload) {
141
+ if (!payload || typeof payload !== "object") {
142
+ return payload;
143
+ }
144
+ if (this.tenantSetter && this.context.tenantId) {
145
+ setNestedValue(payload, this.tenantField, this.context.tenantId);
146
+ }
147
+ if (this.userSetter && this.context.userId) {
148
+ setNestedValue(payload, this.userField, this.context.userId);
149
+ }
150
+ return payload;
151
+ }
152
+ removeSetterFields(payload) {
153
+ if (!payload || typeof payload !== "object") {
154
+ return payload;
155
+ }
156
+ if (this.tenantSetter) {
157
+ this.deleteNestedValue(payload, this.tenantField);
158
+ }
159
+ if (this.userSetter) {
160
+ this.deleteNestedValue(payload, this.userField);
161
+ }
162
+ return payload;
163
+ }
164
+ applyReadFilters(filters = []) {
165
+ const nextFilters = [...filters];
166
+ if (this.tenantFilter && this.context.tenantId) {
167
+ nextFilters.push({ field: this.tenantField, operator: "eq", value: this.context.tenantId });
168
+ }
169
+ if (this.userFilter &&
170
+ this.context.userId &&
171
+ !this.hasSomePermission([this.permission?.All, this.permission?.ViewAll])) {
172
+ nextFilters.push({ field: this.userField, operator: "eq", value: this.context.userId });
173
+ }
174
+ return nextFilters;
175
+ }
176
+ assertReadable(item) {
177
+ if (this.hasSomePermission([this.permission?.All, this.permission?.ViewAll])) {
178
+ this.assertTenant(item);
179
+ return;
180
+ }
181
+ this.assertTenant(item);
182
+ this.assertUser(item);
183
+ }
184
+ assertReadableItems(items) {
185
+ if (!Array.isArray(items)) {
186
+ return;
187
+ }
188
+ items.forEach(item => this.assertReadable(item));
189
+ }
190
+ assertWritable(item, operation) {
191
+ const allPermission = this.permission?.All;
192
+ const operationAllPermission = operation === "update"
193
+ ? this.permission?.UpdateAll
194
+ : this.permission?.DeleteAll;
195
+ if (!this.hasSomePermission([allPermission, operationAllPermission])) {
196
+ this.assertUser(item);
197
+ }
198
+ this.assertTenant(item);
199
+ }
200
+ assertTenant(item) {
201
+ if (!this.tenantAssert || !this.context.tenantId) {
202
+ return;
203
+ }
204
+ const tenantId = this.resolveItemFieldId(item, this.tenantField);
205
+ if (tenantId) {
206
+ this.assertId(this.context.tenantId, tenantId);
207
+ }
208
+ }
209
+ assertUser(item) {
210
+ if (!this.userAssert || !this.context.userId) {
211
+ return;
212
+ }
213
+ const userId = this.resolveItemFieldId(item, this.userField);
214
+ if (userId) {
215
+ this.assertId(this.context.userId, userId);
216
+ }
217
+ }
218
+ assertId(expectedId, actualId) {
219
+ if (expectedId !== actualId) {
220
+ throw new UnauthorizedError();
221
+ }
222
+ }
223
+ hasSomePermission(permissions) {
224
+ const requiredPermissions = permissions.filter((permission) => !!permission);
225
+ if (requiredPermissions.length === 0) {
226
+ return false;
227
+ }
228
+ if (this.context.hasSomePermission?.(requiredPermissions)) {
229
+ return true;
230
+ }
231
+ return requiredPermissions.some(permission => this.context.permissions?.includes(permission));
232
+ }
233
+ resolveItemFieldId(item, field) {
234
+ const value = this.getNestedValue(item, field);
235
+ return this.stringifyRelationId(value);
236
+ }
237
+ getNestedValue(item, path) {
238
+ return path.split(".").reduce((value, key) => value?.[key], item);
239
+ }
240
+ stringifyRelationId(value) {
241
+ if (value === null || value === undefined || value === "") {
242
+ return null;
243
+ }
244
+ const id = value?._id ?? value?.id ?? value;
245
+ if (typeof id === "string" || typeof id === "number" || typeof id === "boolean") {
246
+ return String(id);
247
+ }
248
+ if (typeof id?.toString === "function") {
249
+ const stringId = id.toString();
250
+ return stringId && stringId !== "[object Object]" ? stringId : null;
251
+ }
252
+ return null;
253
+ }
254
+ deleteNestedValue(payload, path) {
255
+ const keys = path.split(".");
256
+ const lastKey = keys.pop();
257
+ if (!lastKey) {
258
+ return;
259
+ }
260
+ const parent = keys.reduce((value, key) => value?.[key], payload);
261
+ if (parent && typeof parent === "object") {
262
+ delete parent[lastKey];
263
+ }
264
+ }
265
+ }
266
+ export default BuildContextTool;
267
+ export { BuildContextTool };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "3.43.0",
6
+ "version": "3.44.0",
7
7
  "description": "Ai utils",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -46,5 +46,5 @@
46
46
  "typescript": "^5.9.3",
47
47
  "vitest": "^3.0.8"
48
48
  },
49
- "gitHead": "9cb1cab8a6fe2a6c574d08596bc6287f5a5311a6"
49
+ "gitHead": "4ba7a86c8b28bba3156bd124a76f3150ba0f676e"
50
50
  }
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ import TTSRoutes from "./routes/TTSRoutes.js";
45
45
  import DraxAgentRoutes from "./routes/DraxAgentRoutes.js";
46
46
  import AgentSessionRoutes from "./routes/AgentSessionRoutes.js";
47
47
  import {DraxAgent} from "./agents/DraxAgent.js";
48
+ import {BuildContextTool} from "./tools/BuildContextTool.js";
48
49
  import type {IAILogRepository} from "./interfaces/IAILogRepository.js";
49
50
  import type {
50
51
  IAIProvider,
@@ -80,6 +81,10 @@ import type {
80
81
  ToolBuilderOptions,
81
82
  ToolBuilderService
82
83
  } from "./interfaces/IBuilderTool.js";
84
+ import type {
85
+ BuildContextToolContext,
86
+ BuildContextToolOptions,
87
+ } from "./tools/BuildContextTool.js";
83
88
  import type {
84
89
  DraxAgentControllerOptions
85
90
  } from "./interfaces/IDraxAgentController.js";
@@ -127,6 +132,8 @@ export type {
127
132
  ToolBuilderMethod,
128
133
  ToolBuilderOptions,
129
134
  ToolBuilderService,
135
+ BuildContextToolContext,
136
+ BuildContextToolOptions,
130
137
  DraxAgentControllerOptions,
131
138
  DraxAgentFastifyRoutesOptions,
132
139
  DraxAgentConfig,
@@ -169,6 +176,7 @@ export {
169
176
  DeepSeekAiProvider,
170
177
  ElevenLabsTTSProvider,
171
178
  BuilderTool,
179
+ BuildContextTool,
172
180
  //Service
173
181
  KnowledgeService,
174
182
  AILogService,