@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 +2 -1
- package/dist/tools/BuildContextTool.js +267 -0
- package/package.json +2 -2
- package/src/index.ts +8 -0
- package/src/tools/BuildContextTool.ts +388 -0
- package/test/BuildContextTool.test.ts +183 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/index.d.ts +4 -2
- package/types/index.d.ts.map +1 -1
- package/types/tools/BuildContextTool.d.ts +33 -0
- package/types/tools/BuildContextTool.d.ts.map +1 -0
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
|
-
|
|
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.
|
|
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": "
|
|
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,
|