@resolveio/server-lib 22.1.31 → 22.2.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/collections/ai-terminal-message.collection.js +8 -0
- package/collections/ai-terminal-message.collection.js.map +1 -1
- package/fixtures/cron-jobs.js +21 -12
- package/fixtures/cron-jobs.js.map +1 -1
- package/managers/worker-dispatcher.manager.js +2 -2
- package/managers/worker-dispatcher.manager.js.map +1 -1
- package/methods/ai-terminal.d.ts +7 -0
- package/methods/ai-terminal.js +591 -307
- package/methods/ai-terminal.js.map +1 -1
- package/methods/cron-jobs.js +14 -4
- package/methods/cron-jobs.js.map +1 -1
- package/methods/mongo-explorer.js +75 -66
- package/methods/mongo-explorer.js.map +1 -1
- package/methods/report-builder.js +1 -1
- package/methods/report-builder.js.map +1 -1
- package/package.json +1 -1
- package/server-app.js +2 -2
- package/server-app.js.map +1 -1
- package/services/codex-client.js +15 -15
- package/services/codex-client.js.map +1 -1
- package/services/openai-client.js +8 -5
- package/services/openai-client.js.map +1 -1
- package/workers/codex-runner.worker.js +1 -1
- package/workers/codex-runner.worker.js.map +1 -1
|
@@ -88,8 +88,9 @@ var simpl_schema_1 = require("simpl-schema");
|
|
|
88
88
|
var user_collection_1 = require("../collections/user.collection");
|
|
89
89
|
var openai_usage_ledger_manager_1 = require("../managers/openai-usage-ledger.manager");
|
|
90
90
|
var resolveio_server_app_1 = require("../resolveio-server-app");
|
|
91
|
-
var
|
|
91
|
+
var codex_client_1 = require("../services/codex-client");
|
|
92
92
|
var common_1 = require("../util/common");
|
|
93
|
+
var tokenizer_1 = require("../util/tokenizer");
|
|
93
94
|
var DEFAULT_LIMIT = 100;
|
|
94
95
|
var MAX_LIMIT = 2000;
|
|
95
96
|
var ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
@@ -140,14 +141,6 @@ function normalizeExplorerMode(mode) {
|
|
|
140
141
|
}
|
|
141
142
|
return 'aicoder';
|
|
142
143
|
}
|
|
143
|
-
function isAdminUser(user) {
|
|
144
|
-
var _a;
|
|
145
|
-
if (!user) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
var username = String(user.username || '').trim().toLowerCase();
|
|
149
|
-
return username === 'admin' || ((_a = user.roles) === null || _a === void 0 ? void 0 : _a.super_admin) === true;
|
|
150
|
-
}
|
|
151
144
|
function allowUnschemaizedWrites() {
|
|
152
145
|
return process.env.MONGO_EXPLORER_ALLOW_UNSCHEMATIZED_WRITE === 'true';
|
|
153
146
|
}
|
|
@@ -403,8 +396,8 @@ function ensureWriteAccess(context, permissionView, mode) {
|
|
|
403
396
|
throw new Error('Mongo Explorer: Readonly user');
|
|
404
397
|
}
|
|
405
398
|
normalizedMode = normalizeExplorerMode(mode);
|
|
406
|
-
if (normalizedMode === 'resolveio'
|
|
407
|
-
throw new Error('Mongo Explorer: ResolveIO mode is read only
|
|
399
|
+
if (normalizedMode === 'resolveio') {
|
|
400
|
+
throw new Error('Mongo Explorer: ResolveIO mode is read only');
|
|
408
401
|
}
|
|
409
402
|
allowedUsers = parseMongoExplorerWriteUsers();
|
|
410
403
|
if (allowedUsers.length) {
|
|
@@ -737,7 +730,7 @@ function normalizeRiskReview(operation, payload, model, requestId) {
|
|
|
737
730
|
? Math.max(0, Math.min(1, normalizedConfidence))
|
|
738
731
|
: 0.6;
|
|
739
732
|
var summary = normalizeOptionalString(payload === null || payload === void 0 ? void 0 : payload.summary)
|
|
740
|
-
|| "
|
|
733
|
+
|| "AI review marked this operation as ".concat(riskLevel, " risk.");
|
|
741
734
|
var reasons = normalizeRiskList(payload === null || payload === void 0 ? void 0 : payload.reasons);
|
|
742
735
|
var suggestedChecks = normalizeRiskList(payload === null || payload === void 0 ? void 0 : payload.suggested_checks);
|
|
743
736
|
var shouldBlock = (payload === null || payload === void 0 ? void 0 : payload.should_block) === true || riskLevel === 'critical';
|
|
@@ -791,6 +784,26 @@ function resolveRiskReviewSettings() {
|
|
|
791
784
|
retryDelayMs: retryDelayMs
|
|
792
785
|
};
|
|
793
786
|
}
|
|
787
|
+
function buildCodexPrompt(systemPrompt, userPrompt) {
|
|
788
|
+
return "System:\n".concat(systemPrompt, "\n\nUser:\n").concat(userPrompt).trim();
|
|
789
|
+
}
|
|
790
|
+
function buildCodexClient(settings) {
|
|
791
|
+
var fallbackModels = [];
|
|
792
|
+
var fallback = normalizeOptionalString(settings.fallbackModel);
|
|
793
|
+
if (fallback && fallback !== settings.model) {
|
|
794
|
+
fallbackModels.push(fallback);
|
|
795
|
+
}
|
|
796
|
+
return new codex_client_1.CodexClient(__assign(__assign({ apiKey: settings.apiKey, baseUrl: settings.baseUrl, model: settings.model }, (fallbackModels.length ? { fallbackModel: fallbackModels[0], fallbackModels: fallbackModels } : {})), { maxRetries: (0, common_1.round)(settings.maxRetries || 0), retryDelayMs: (0, common_1.round)(settings.retryDelayMs || 0) }));
|
|
797
|
+
}
|
|
798
|
+
function estimateCodexUsage(messages, responseText, model) {
|
|
799
|
+
var inputTokens = (0, tokenizer_1.countChatTokens)(messages, model);
|
|
800
|
+
var outputTokens = (0, tokenizer_1.countTokens)(responseText || '', model);
|
|
801
|
+
return {
|
|
802
|
+
inputTokens: inputTokens,
|
|
803
|
+
outputTokens: outputTokens,
|
|
804
|
+
totalTokens: inputTokens + outputTokens
|
|
805
|
+
};
|
|
806
|
+
}
|
|
794
807
|
function buildRiskReviewPrompt(input) {
|
|
795
808
|
var payload = {
|
|
796
809
|
database: input.database,
|
|
@@ -811,7 +824,7 @@ function buildRiskReviewPrompt(input) {
|
|
|
811
824
|
}
|
|
812
825
|
function reviewOperationRisk(input) {
|
|
813
826
|
return __awaiter(this, void 0, void 0, function () {
|
|
814
|
-
var settings, client, systemPrompt,
|
|
827
|
+
var settings, client, systemPrompt, userPrompt, prompt, responseText, payload, err_1, detail;
|
|
815
828
|
return __generator(this, function (_a) {
|
|
816
829
|
switch (_a.label) {
|
|
817
830
|
case 0:
|
|
@@ -820,19 +833,9 @@ function reviewOperationRisk(input) {
|
|
|
820
833
|
return [2 /*return*/, buildDisabledRiskReview(input.operation)];
|
|
821
834
|
}
|
|
822
835
|
if (!settings.apiKey) {
|
|
823
|
-
return [2 /*return*/, buildFallbackRiskReview(input.operation, 'AI risk review unavailable:
|
|
836
|
+
return [2 /*return*/, buildFallbackRiskReview(input.operation, 'AI risk review unavailable: AI API key is missing.')];
|
|
824
837
|
}
|
|
825
|
-
client =
|
|
826
|
-
apiKey: settings.apiKey,
|
|
827
|
-
baseUrl: settings.baseUrl,
|
|
828
|
-
model: settings.model,
|
|
829
|
-
fallbackModel: settings.fallbackModel,
|
|
830
|
-
temperature: 0.1,
|
|
831
|
-
maxTokens: settings.maxTokens,
|
|
832
|
-
maxRetries: (0, common_1.round)(settings.maxRetries),
|
|
833
|
-
retryDelayMs: (0, common_1.round)(settings.retryDelayMs),
|
|
834
|
-
responseFormat: 'json'
|
|
835
|
-
});
|
|
838
|
+
client = buildCodexClient(settings);
|
|
836
839
|
systemPrompt = [
|
|
837
840
|
'You are a MongoDB operation safety reviewer for a production SaaS application.',
|
|
838
841
|
'Respond with a single JSON object only.',
|
|
@@ -845,20 +848,27 @@ function reviewOperationRisk(input) {
|
|
|
845
848
|
'confidence (number between 0 and 1).',
|
|
846
849
|
'Keep summary concise (<= 220 chars).'
|
|
847
850
|
].join(' ');
|
|
851
|
+
userPrompt = buildRiskReviewPrompt(input);
|
|
852
|
+
prompt = buildCodexPrompt(systemPrompt, userPrompt);
|
|
848
853
|
_a.label = 1;
|
|
849
854
|
case 1:
|
|
850
855
|
_a.trys.push([1, 3, , 4]);
|
|
851
|
-
return [4 /*yield*/, client.
|
|
852
|
-
{ role: 'system', content: systemPrompt },
|
|
853
|
-
{ role: 'user', content: buildRiskReviewPrompt(input) }
|
|
854
|
-
], {
|
|
856
|
+
return [4 /*yield*/, client.run(prompt, {
|
|
855
857
|
timeoutMs: (0, common_1.round)(settings.timeoutMs),
|
|
856
|
-
|
|
858
|
+
threadOptions: {
|
|
859
|
+
model: settings.model,
|
|
860
|
+
sandboxMode: 'read-only',
|
|
861
|
+
skipGitRepoCheck: true,
|
|
862
|
+
networkAccessEnabled: false,
|
|
863
|
+
webSearchMode: 'disabled',
|
|
864
|
+
webSearchEnabled: false,
|
|
865
|
+
approvalPolicy: 'never'
|
|
866
|
+
}
|
|
857
867
|
})];
|
|
858
868
|
case 2:
|
|
859
|
-
|
|
860
|
-
payload = parseRiskReviewPayload(
|
|
861
|
-
return [2 /*return*/, normalizeRiskReview(input.operation, payload,
|
|
869
|
+
responseText = _a.sent();
|
|
870
|
+
payload = parseRiskReviewPayload(responseText);
|
|
871
|
+
return [2 /*return*/, normalizeRiskReview(input.operation, payload, settings.model, '')];
|
|
862
872
|
case 3:
|
|
863
873
|
err_1 = _a.sent();
|
|
864
874
|
detail = (err_1 === null || err_1 === void 0 ? void 0 : err_1.message) ? String(err_1.message) : 'Unknown AI review error';
|
|
@@ -1155,7 +1165,7 @@ function resolveUsageClientId(idClientInput, idUser) {
|
|
|
1155
1165
|
}
|
|
1156
1166
|
function executeMongoExplorerAi(payload, context) {
|
|
1157
1167
|
return __awaiter(this, void 0, void 0, function () {
|
|
1158
|
-
var input, prompt, database, db, availableCollections, listed, selectedCollection, availableFields, settings, maxResults, client,
|
|
1168
|
+
var input, prompt, database, db, availableCollections, listed, selectedCollection, availableFields, settings, maxResults, client, messages, responseText, parsed, action, collection, plan, removedRestrictedStages, optionsRaw, aggregateLimit, pipelineResult, aggregateOptions, aggregateRows, rows, query, options, findOptions, rows, total, _a, usage, idClient;
|
|
1159
1169
|
var _b;
|
|
1160
1170
|
return __generator(this, function (_c) {
|
|
1161
1171
|
switch (_c.label) {
|
|
@@ -1188,39 +1198,38 @@ function executeMongoExplorerAi(payload, context) {
|
|
|
1188
1198
|
}
|
|
1189
1199
|
settings = resolveMongoExplorerAiSettings();
|
|
1190
1200
|
if (!settings.apiKey) {
|
|
1191
|
-
throw new Error('
|
|
1201
|
+
throw new Error('AI API key missing. Add an AI API key to server config.');
|
|
1192
1202
|
}
|
|
1193
1203
|
maxResults = normalizeAiResultLimit(input.max_results, 100);
|
|
1194
|
-
client =
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
content: buildMongoExplorerAiUserPrompt({
|
|
1210
|
-
prompt: prompt,
|
|
1211
|
-
selectedCollection: selectedCollection,
|
|
1212
|
-
availableCollections: availableCollections,
|
|
1213
|
-
availableFields: availableFields,
|
|
1214
|
-
maxResults: maxResults
|
|
1215
|
-
})
|
|
1216
|
-
}
|
|
1217
|
-
], {
|
|
1204
|
+
client = buildCodexClient(settings);
|
|
1205
|
+
messages = [
|
|
1206
|
+
{ role: 'system', content: buildMongoExplorerAiSystemPrompt() },
|
|
1207
|
+
{
|
|
1208
|
+
role: 'user',
|
|
1209
|
+
content: buildMongoExplorerAiUserPrompt({
|
|
1210
|
+
prompt: prompt,
|
|
1211
|
+
selectedCollection: selectedCollection,
|
|
1212
|
+
availableCollections: availableCollections,
|
|
1213
|
+
availableFields: availableFields,
|
|
1214
|
+
maxResults: maxResults
|
|
1215
|
+
})
|
|
1216
|
+
}
|
|
1217
|
+
];
|
|
1218
|
+
return [4 /*yield*/, client.run(buildCodexPrompt(messages[0].content, messages[1].content), {
|
|
1218
1219
|
timeoutMs: (0, common_1.round)(settings.timeoutMs),
|
|
1219
|
-
|
|
1220
|
+
threadOptions: {
|
|
1221
|
+
model: settings.model,
|
|
1222
|
+
sandboxMode: 'read-only',
|
|
1223
|
+
skipGitRepoCheck: true,
|
|
1224
|
+
networkAccessEnabled: false,
|
|
1225
|
+
webSearchMode: 'disabled',
|
|
1226
|
+
webSearchEnabled: false,
|
|
1227
|
+
approvalPolicy: 'never'
|
|
1228
|
+
}
|
|
1220
1229
|
})];
|
|
1221
1230
|
case 3:
|
|
1222
|
-
|
|
1223
|
-
parsed = parseAiPlanPayload(
|
|
1231
|
+
responseText = _c.sent();
|
|
1232
|
+
parsed = parseAiPlanPayload(responseText);
|
|
1224
1233
|
action = normalizeAiAction((parsed === null || parsed === void 0 ? void 0 : parsed.action) || (Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.pipeline) ? 'aggregate' : 'find'));
|
|
1225
1234
|
collection = resolveCollectionFromList((parsed === null || parsed === void 0 ? void 0 : parsed.collection) || (parsed === null || parsed === void 0 ? void 0 : parsed.collection_name), availableCollections, selectedCollection || availableCollections[0]);
|
|
1226
1235
|
if (!collection) {
|
|
@@ -1293,19 +1302,19 @@ function executeMongoExplorerAi(payload, context) {
|
|
|
1293
1302
|
_c.label = 10;
|
|
1294
1303
|
case 10:
|
|
1295
1304
|
plan.notes = buildMongoExplorerAiNotes(parsed === null || parsed === void 0 ? void 0 : parsed.notes, plan.action, plan.collection, Array.isArray(plan.documents) ? plan.documents.length : 0, typeof plan.total === 'number' ? plan.total : null, removedRestrictedStages);
|
|
1296
|
-
usage =
|
|
1305
|
+
usage = estimateCodexUsage(messages, responseText, settings.model);
|
|
1297
1306
|
return [4 /*yield*/, resolveUsageClientId(input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
|
|
1298
1307
|
case 11:
|
|
1299
1308
|
idClient = _c.sent();
|
|
1300
1309
|
if (!(idClient && usage.totalTokens)) return [3 /*break*/, 13];
|
|
1301
1310
|
return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
|
|
1302
1311
|
id_client: idClient,
|
|
1303
|
-
model:
|
|
1312
|
+
model: settings.model || 'unknown',
|
|
1304
1313
|
input_tokens: usage.inputTokens || 0,
|
|
1305
1314
|
output_tokens: usage.outputTokens || 0,
|
|
1306
1315
|
total_tokens: usage.totalTokens || 0,
|
|
1307
1316
|
category: 'mongo-explorer-ai',
|
|
1308
|
-
id_request:
|
|
1317
|
+
id_request: ''
|
|
1309
1318
|
})];
|
|
1310
1319
|
case 12:
|
|
1311
1320
|
_c.sent();
|
|
@@ -1313,7 +1322,7 @@ function executeMongoExplorerAi(payload, context) {
|
|
|
1313
1322
|
case 13: return [2 /*return*/, {
|
|
1314
1323
|
notes: plan.notes,
|
|
1315
1324
|
plan: plan,
|
|
1316
|
-
model:
|
|
1325
|
+
model: settings.model,
|
|
1317
1326
|
usage: {
|
|
1318
1327
|
input_tokens: usage.inputTokens || 0,
|
|
1319
1328
|
output_tokens: usage.outputTokens || 0,
|