@resolveio/server-lib 22.1.21 → 22.1.23
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/managers/method.manager.js +1 -1
- package/managers/method.manager.js.map +1 -1
- package/methods/ai-terminal.js +47 -86
- package/methods/ai-terminal.js.map +1 -1
- package/methods/mongo-explorer.js +491 -0
- package/methods/mongo-explorer.js.map +1 -1
- package/methods.ts +3 -0
- package/package.json +1 -1
- package/services/codex-client.js +16 -6
- package/services/codex-client.js.map +1 -1
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
2
13
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
14
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
15
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -75,6 +86,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
75
86
|
exports.loadMongoExplorerMethods = loadMongoExplorerMethods;
|
|
76
87
|
var simpl_schema_1 = require("simpl-schema");
|
|
77
88
|
var user_collection_1 = require("../collections/user.collection");
|
|
89
|
+
var openai_usage_ledger_manager_1 = require("../managers/openai-usage-ledger.manager");
|
|
78
90
|
var resolveio_server_app_1 = require("../resolveio-server-app");
|
|
79
91
|
var openai_client_1 = require("../services/openai-client");
|
|
80
92
|
var common_1 = require("../util/common");
|
|
@@ -91,6 +103,14 @@ var DEFAULT_RISK_REVIEW_TIMEOUT_MS = 30000;
|
|
|
91
103
|
var DEFAULT_RISK_REVIEW_MAX_TOKENS = 700;
|
|
92
104
|
var DEFAULT_RISK_REVIEW_MODEL = 'gpt-5.3-codex';
|
|
93
105
|
var SENSITIVE_REVIEW_FIELD_REGEX = /(password|secret|token|api[_-]?key|salt|hash|email|phone|address|ssn|services|roles)/i;
|
|
106
|
+
var DEFAULT_AI_SUGGEST_TIMEOUT_MS = 60000;
|
|
107
|
+
var DEFAULT_AI_SUGGEST_MAX_TOKENS = 1000;
|
|
108
|
+
var DEFAULT_AI_SUGGEST_MODEL = 'gpt-5.3-codex';
|
|
109
|
+
var DEFAULT_AI_SUGGEST_FALLBACK_MODEL = 'gpt-5.2-codex';
|
|
110
|
+
var MAX_AI_SUGGEST_FIELDS = 700;
|
|
111
|
+
var MAX_AI_SUGGEST_COLLECTIONS = 800;
|
|
112
|
+
var MAX_AI_SUGGEST_RESULTS = 500;
|
|
113
|
+
var RESTRICTED_AGGREGATE_STAGES = new Set(['$out', '$merge']);
|
|
94
114
|
function parseMongoExplorerWriteUsers() {
|
|
95
115
|
var raw = typeof process.env.MONGO_EXPLORER_WRITE_USERS === 'string' ? process.env.MONGO_EXPLORER_WRITE_USERS.trim() : '';
|
|
96
116
|
if (!raw) {
|
|
@@ -848,8 +868,479 @@ function reviewOperationRisk(input) {
|
|
|
848
868
|
});
|
|
849
869
|
});
|
|
850
870
|
}
|
|
871
|
+
function normalizeAiAction(value) {
|
|
872
|
+
var normalized = normalizeOptionalString(value) || '';
|
|
873
|
+
return normalized.toLowerCase() === 'aggregate' ? 'aggregate' : 'find';
|
|
874
|
+
}
|
|
875
|
+
function sanitizeAiCollections(raw) {
|
|
876
|
+
var values = [];
|
|
877
|
+
var seen = new Set();
|
|
878
|
+
(raw || []).forEach(function (entry) {
|
|
879
|
+
var normalized = normalizeOptionalString((entry === null || entry === void 0 ? void 0 : entry.collection) || (entry === null || entry === void 0 ? void 0 : entry.name) || entry);
|
|
880
|
+
if (!normalized) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
var key = normalized.toLowerCase();
|
|
884
|
+
if (seen.has(key)) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
seen.add(key);
|
|
888
|
+
values.push(normalized);
|
|
889
|
+
});
|
|
890
|
+
return values.slice(0, MAX_AI_SUGGEST_COLLECTIONS);
|
|
891
|
+
}
|
|
892
|
+
function sanitizeAiFields(raw, fallbackCollection) {
|
|
893
|
+
var fields = [];
|
|
894
|
+
var seen = new Set();
|
|
895
|
+
(raw || []).forEach(function (entry) {
|
|
896
|
+
var path = normalizeOptionalString((entry === null || entry === void 0 ? void 0 : entry.path) || (entry === null || entry === void 0 ? void 0 : entry.field_path) || (entry === null || entry === void 0 ? void 0 : entry.fieldPath));
|
|
897
|
+
if (!path) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
var collection = normalizeOptionalString((entry === null || entry === void 0 ? void 0 : entry.collection) || (entry === null || entry === void 0 ? void 0 : entry.collection_name) || (entry === null || entry === void 0 ? void 0 : entry.collectionName)) || fallbackCollection || '';
|
|
901
|
+
var key = "".concat(collection.toLowerCase(), "::").concat(path.toLowerCase());
|
|
902
|
+
if (seen.has(key)) {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
seen.add(key);
|
|
906
|
+
fields.push({
|
|
907
|
+
path: path,
|
|
908
|
+
label: normalizeOptionalString((entry === null || entry === void 0 ? void 0 : entry.label) || (entry === null || entry === void 0 ? void 0 : entry.field_path_name) || (entry === null || entry === void 0 ? void 0 : entry.fieldPathName)) || path,
|
|
909
|
+
type: normalizeOptionalString((entry === null || entry === void 0 ? void 0 : entry.type) || (entry === null || entry === void 0 ? void 0 : entry.field_type) || (entry === null || entry === void 0 ? void 0 : entry.fieldType)) || 'Any',
|
|
910
|
+
collection: collection
|
|
911
|
+
});
|
|
912
|
+
});
|
|
913
|
+
return fields.slice(0, MAX_AI_SUGGEST_FIELDS);
|
|
914
|
+
}
|
|
915
|
+
function deriveAiFieldsFromCollection(database, collection) {
|
|
916
|
+
if (!collection) {
|
|
917
|
+
return [];
|
|
918
|
+
}
|
|
919
|
+
var managerCollection = resolveCollectionHandle(database, collection).managerCollection;
|
|
920
|
+
if (!managerCollection) {
|
|
921
|
+
return [];
|
|
922
|
+
}
|
|
923
|
+
var schema = getSchemaDefinition(managerCollection);
|
|
924
|
+
return Object.keys(schema)
|
|
925
|
+
.sort(function (a, b) { return a.localeCompare(b); })
|
|
926
|
+
.slice(0, MAX_AI_SUGGEST_FIELDS)
|
|
927
|
+
.map(function (path) {
|
|
928
|
+
var definition = schema[path];
|
|
929
|
+
return {
|
|
930
|
+
path: path,
|
|
931
|
+
label: toLabel(path),
|
|
932
|
+
type: getSchemaTypeName(definition),
|
|
933
|
+
collection: collection
|
|
934
|
+
};
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
function resolveCollectionFromList(value, collections, fallback) {
|
|
938
|
+
if (fallback === void 0) { fallback = ''; }
|
|
939
|
+
var normalized = normalizeOptionalString(value);
|
|
940
|
+
if (normalized) {
|
|
941
|
+
var matched = (collections || []).find(function (entry) { return entry.toLowerCase() === normalized.toLowerCase(); });
|
|
942
|
+
if (matched) {
|
|
943
|
+
return matched;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (fallback) {
|
|
947
|
+
return fallback;
|
|
948
|
+
}
|
|
949
|
+
return (collections === null || collections === void 0 ? void 0 : collections[0]) || '';
|
|
950
|
+
}
|
|
951
|
+
function normalizeAiResultLimit(value, fallback) {
|
|
952
|
+
if (fallback === void 0) { fallback = 100; }
|
|
953
|
+
var fallbackValue = Math.min(Math.max(fallback, 1), MAX_AI_SUGGEST_RESULTS);
|
|
954
|
+
var parsed = Number(value);
|
|
955
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
956
|
+
return fallbackValue;
|
|
957
|
+
}
|
|
958
|
+
return Math.min(Math.max((0, common_1.round)(parsed), 1), MAX_AI_SUGGEST_RESULTS);
|
|
959
|
+
}
|
|
960
|
+
function normalizeAiSkip(value) {
|
|
961
|
+
var parsed = Number(value);
|
|
962
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
963
|
+
return 0;
|
|
964
|
+
}
|
|
965
|
+
return Math.max(0, (0, common_1.round)(parsed));
|
|
966
|
+
}
|
|
967
|
+
function normalizeAiObject(value) {
|
|
968
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
969
|
+
return {};
|
|
970
|
+
}
|
|
971
|
+
return value;
|
|
972
|
+
}
|
|
973
|
+
function hasObjectKeys(value) {
|
|
974
|
+
return !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
975
|
+
}
|
|
976
|
+
function parseAiPlanPayload(content) {
|
|
977
|
+
var normalized = String(content || '').trim();
|
|
978
|
+
if (!normalized.length) {
|
|
979
|
+
return {};
|
|
980
|
+
}
|
|
981
|
+
try {
|
|
982
|
+
return JSON.parse(normalized);
|
|
983
|
+
}
|
|
984
|
+
catch (_a) {
|
|
985
|
+
// Fall through and parse embedded JSON object.
|
|
986
|
+
}
|
|
987
|
+
var start = normalized.indexOf('{');
|
|
988
|
+
var end = normalized.lastIndexOf('}');
|
|
989
|
+
if (start !== -1 && end > start) {
|
|
990
|
+
try {
|
|
991
|
+
return JSON.parse(normalized.slice(start, end + 1));
|
|
992
|
+
}
|
|
993
|
+
catch (_b) {
|
|
994
|
+
return {};
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return {};
|
|
998
|
+
}
|
|
999
|
+
function resolveMongoExplorerAiSettings() {
|
|
1000
|
+
var _a, _b, _c, _d;
|
|
1001
|
+
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
1002
|
+
var apiKey = normalizeOptionalString(serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY) || '';
|
|
1003
|
+
var baseUrl = normalizeOptionalString(serverConfig['OPENAI_BASE_URL'] || process.env.OPENAI_BASE_URL);
|
|
1004
|
+
var model = normalizeOptionalString(serverConfig['MONGO_EXPLORER_AI_MODEL']
|
|
1005
|
+
|| process.env.MONGO_EXPLORER_AI_MODEL
|
|
1006
|
+
|| serverConfig['AI_ASSISTANT_CODEX_MODEL']
|
|
1007
|
+
|| process.env.AI_ASSISTANT_CODEX_MODEL
|
|
1008
|
+
|| serverConfig['OPENAI_MODEL']
|
|
1009
|
+
|| process.env.OPENAI_MODEL) || DEFAULT_AI_SUGGEST_MODEL;
|
|
1010
|
+
var fallbackModel = normalizeOptionalString(serverConfig['MONGO_EXPLORER_AI_FALLBACK_MODEL']
|
|
1011
|
+
|| process.env.MONGO_EXPLORER_AI_FALLBACK_MODEL
|
|
1012
|
+
|| serverConfig['AI_ASSISTANT_CODEX_FALLBACK_MODEL']
|
|
1013
|
+
|| process.env.AI_ASSISTANT_CODEX_FALLBACK_MODEL) || DEFAULT_AI_SUGGEST_FALLBACK_MODEL;
|
|
1014
|
+
var timeoutMs = normalizePositiveNumber((_a = serverConfig['MONGO_EXPLORER_AI_TIMEOUT_MS']) !== null && _a !== void 0 ? _a : process.env.MONGO_EXPLORER_AI_TIMEOUT_MS, DEFAULT_AI_SUGGEST_TIMEOUT_MS);
|
|
1015
|
+
var maxTokens = normalizePositiveNumber((_b = serverConfig['MONGO_EXPLORER_AI_MAX_TOKENS']) !== null && _b !== void 0 ? _b : process.env.MONGO_EXPLORER_AI_MAX_TOKENS, DEFAULT_AI_SUGGEST_MAX_TOKENS);
|
|
1016
|
+
var maxRetries = normalizePositiveNumber((_c = serverConfig['OPENAI_MAX_RETRIES']) !== null && _c !== void 0 ? _c : process.env.OPENAI_MAX_RETRIES, 1);
|
|
1017
|
+
var retryDelayMs = normalizePositiveNumber((_d = serverConfig['OPENAI_RETRY_DELAY_MS']) !== null && _d !== void 0 ? _d : process.env.OPENAI_RETRY_DELAY_MS, 750);
|
|
1018
|
+
return {
|
|
1019
|
+
apiKey: apiKey,
|
|
1020
|
+
baseUrl: baseUrl,
|
|
1021
|
+
model: model,
|
|
1022
|
+
fallbackModel: fallbackModel,
|
|
1023
|
+
timeoutMs: timeoutMs,
|
|
1024
|
+
maxTokens: maxTokens,
|
|
1025
|
+
maxRetries: maxRetries,
|
|
1026
|
+
retryDelayMs: retryDelayMs
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function buildMongoExplorerAiSystemPrompt() {
|
|
1030
|
+
return [
|
|
1031
|
+
'You are a MongoDB query planner for a read-only Mongo Explorer UI.',
|
|
1032
|
+
'Return a single JSON object and nothing else.',
|
|
1033
|
+
'Supported schema:',
|
|
1034
|
+
'{',
|
|
1035
|
+
' "action": "find|aggregate",',
|
|
1036
|
+
' "collection": "string",',
|
|
1037
|
+
' "query": { ... },',
|
|
1038
|
+
' "pipeline": [{ ... }],',
|
|
1039
|
+
' "options": {',
|
|
1040
|
+
' "projection": { "field": 1 },',
|
|
1041
|
+
' "sort": { "field": -1 },',
|
|
1042
|
+
' "limit": 100,',
|
|
1043
|
+
' "skip": 0,',
|
|
1044
|
+
' "includeTotal": true,',
|
|
1045
|
+
' "allowDiskUse": true',
|
|
1046
|
+
' },',
|
|
1047
|
+
' "notes": "short summary"',
|
|
1048
|
+
'}',
|
|
1049
|
+
'Rules:',
|
|
1050
|
+
'- Use only provided collection names and field paths.',
|
|
1051
|
+
'- Read-only only. Never output write operations, update/delete commands, or aggregation stages $out/$merge.',
|
|
1052
|
+
'- Prefer action=find for direct lookups and simple filters.',
|
|
1053
|
+
'- Use action=aggregate for grouped totals, rankings, or trend buckets.',
|
|
1054
|
+
'- Keep options.limit between 1 and 500.',
|
|
1055
|
+
'- If request is ambiguous, use selected_collection and a conservative limit.'
|
|
1056
|
+
].join('\n');
|
|
1057
|
+
}
|
|
1058
|
+
function buildMongoExplorerAiUserPrompt(input) {
|
|
1059
|
+
var payload = {
|
|
1060
|
+
request: input.prompt,
|
|
1061
|
+
selected_collection: input.selectedCollection || '',
|
|
1062
|
+
max_results: input.maxResults,
|
|
1063
|
+
available_collections: input.availableCollections || [],
|
|
1064
|
+
available_fields: input.availableFields || []
|
|
1065
|
+
};
|
|
1066
|
+
return JSON.stringify(payload);
|
|
1067
|
+
}
|
|
1068
|
+
function sanitizeAggregatePipeline(rawPipeline, limit) {
|
|
1069
|
+
var source = Array.isArray(rawPipeline) ? rawPipeline : [];
|
|
1070
|
+
var sanitized = [];
|
|
1071
|
+
var removedRestricted = false;
|
|
1072
|
+
source.forEach(function (stage) {
|
|
1073
|
+
if (!stage || typeof stage !== 'object' || Array.isArray(stage)) {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
var keys = Object.keys(stage);
|
|
1077
|
+
if (!keys.length) {
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
var stageName = keys[0];
|
|
1081
|
+
if (RESTRICTED_AGGREGATE_STAGES.has(String(stageName).toLowerCase())) {
|
|
1082
|
+
removedRestricted = true;
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
if (stageName === '$limit') {
|
|
1086
|
+
sanitized.push({ $limit: normalizeAiResultLimit(stage.$limit, limit) });
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
sanitized.push(stage);
|
|
1090
|
+
});
|
|
1091
|
+
if (!sanitized.some(function (stage) { return Object.keys(stage || {})[0] === '$limit'; })) {
|
|
1092
|
+
sanitized.push({ $limit: limit });
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
pipeline: sanitized,
|
|
1096
|
+
removedRestricted: removedRestricted
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
function sanitizeFindOptions(raw, fallbackLimit) {
|
|
1100
|
+
var options = normalizeAiObject(raw);
|
|
1101
|
+
return {
|
|
1102
|
+
projection: hasObjectKeys(options.projection) ? options.projection : undefined,
|
|
1103
|
+
sort: hasObjectKeys(options.sort) ? options.sort : undefined,
|
|
1104
|
+
limit: normalizeAiResultLimit(options.limit, fallbackLimit),
|
|
1105
|
+
skip: normalizeAiSkip(options.skip),
|
|
1106
|
+
includeTotal: options.includeTotal === true
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function buildMongoExplorerAiNotes(rawNotes, action, collection, rowCount, total, removedRestricted) {
|
|
1110
|
+
var notes = [];
|
|
1111
|
+
var base = normalizeOptionalString(rawNotes);
|
|
1112
|
+
if (base) {
|
|
1113
|
+
notes.push(base);
|
|
1114
|
+
}
|
|
1115
|
+
var actionLabel = action === 'aggregate' ? 'aggregate pipeline' : 'query';
|
|
1116
|
+
if (typeof total === 'number' && total >= 0) {
|
|
1117
|
+
notes.push("Applied ".concat(actionLabel, " on ").concat(collection, ". Loaded ").concat(rowCount, " of ").concat(total, " rows."));
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
notes.push("Applied ".concat(actionLabel, " on ").concat(collection, ". Loaded ").concat(rowCount, " rows."));
|
|
1121
|
+
}
|
|
1122
|
+
if (removedRestricted) {
|
|
1123
|
+
notes.push('Removed restricted write stages from the generated pipeline.');
|
|
1124
|
+
}
|
|
1125
|
+
return notes.join(' ').trim();
|
|
1126
|
+
}
|
|
1127
|
+
function resolveUsageClientId(idClientInput, idUser) {
|
|
1128
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1129
|
+
var normalized, user, _a;
|
|
1130
|
+
var _b, _c;
|
|
1131
|
+
return __generator(this, function (_d) {
|
|
1132
|
+
switch (_d.label) {
|
|
1133
|
+
case 0:
|
|
1134
|
+
normalized = normalizeOptionalString(idClientInput);
|
|
1135
|
+
if (normalized) {
|
|
1136
|
+
return [2 /*return*/, normalized];
|
|
1137
|
+
}
|
|
1138
|
+
if (!idUser) {
|
|
1139
|
+
return [2 /*return*/, ''];
|
|
1140
|
+
}
|
|
1141
|
+
_d.label = 1;
|
|
1142
|
+
case 1:
|
|
1143
|
+
_d.trys.push([1, 3, , 4]);
|
|
1144
|
+
return [4 /*yield*/, user_collection_1.Users.findById(idUser)];
|
|
1145
|
+
case 2:
|
|
1146
|
+
user = _d.sent();
|
|
1147
|
+
return [2 /*return*/, normalizeOptionalString(((_b = user === null || user === void 0 ? void 0 : user.other) === null || _b === void 0 ? void 0 : _b.id_client) || ((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.idClient)) || ''];
|
|
1148
|
+
case 3:
|
|
1149
|
+
_a = _d.sent();
|
|
1150
|
+
return [2 /*return*/, ''];
|
|
1151
|
+
case 4: return [2 /*return*/];
|
|
1152
|
+
}
|
|
1153
|
+
});
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
function executeMongoExplorerAi(payload, context) {
|
|
1157
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1158
|
+
var input, prompt, database, db, availableCollections, listed, selectedCollection, availableFields, settings, maxResults, client, response, parsed, action, collection, plan, removedRestrictedStages, optionsRaw, aggregateLimit, pipelineResult, aggregateOptions, aggregateRows, rows, query, options, findOptions, rows, total, _a, usage, idClient;
|
|
1159
|
+
var _b;
|
|
1160
|
+
return __generator(this, function (_c) {
|
|
1161
|
+
switch (_c.label) {
|
|
1162
|
+
case 0:
|
|
1163
|
+
input = payload || {};
|
|
1164
|
+
prompt = normalizeOptionalString(input.prompt);
|
|
1165
|
+
if (!prompt) {
|
|
1166
|
+
throw new Error('Prompt is required.');
|
|
1167
|
+
}
|
|
1168
|
+
database = resolveDatabaseName(input.database);
|
|
1169
|
+
db = resolveDatabase(database);
|
|
1170
|
+
availableCollections = sanitizeAiCollections(input.available_collections || []);
|
|
1171
|
+
if (!!availableCollections.length) return [3 /*break*/, 2];
|
|
1172
|
+
return [4 /*yield*/, db.listCollections().toArray()];
|
|
1173
|
+
case 1:
|
|
1174
|
+
listed = _c.sent();
|
|
1175
|
+
availableCollections = listed
|
|
1176
|
+
.map(function (collection) { return normalizeOptionalString(collection === null || collection === void 0 ? void 0 : collection.name); })
|
|
1177
|
+
.filter(function (collection) { return !!collection; })
|
|
1178
|
+
.slice(0, MAX_AI_SUGGEST_COLLECTIONS);
|
|
1179
|
+
_c.label = 2;
|
|
1180
|
+
case 2:
|
|
1181
|
+
if (!availableCollections.length) {
|
|
1182
|
+
throw new Error('Mongo Explorer AI assistant: no collections available.');
|
|
1183
|
+
}
|
|
1184
|
+
selectedCollection = resolveCollectionFromList(input.selected_collection, availableCollections, availableCollections[0]);
|
|
1185
|
+
availableFields = sanitizeAiFields(input.available_fields || [], selectedCollection);
|
|
1186
|
+
if (!availableFields.length && selectedCollection) {
|
|
1187
|
+
availableFields = deriveAiFieldsFromCollection(database, selectedCollection);
|
|
1188
|
+
}
|
|
1189
|
+
settings = resolveMongoExplorerAiSettings();
|
|
1190
|
+
if (!settings.apiKey) {
|
|
1191
|
+
throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
|
|
1192
|
+
}
|
|
1193
|
+
maxResults = normalizeAiResultLimit(input.max_results, 100);
|
|
1194
|
+
client = new openai_client_1.OpenAIClient({
|
|
1195
|
+
apiKey: settings.apiKey,
|
|
1196
|
+
baseUrl: settings.baseUrl,
|
|
1197
|
+
model: settings.model,
|
|
1198
|
+
fallbackModel: settings.fallbackModel,
|
|
1199
|
+
temperature: 0.1,
|
|
1200
|
+
maxTokens: (0, common_1.round)(settings.maxTokens),
|
|
1201
|
+
maxRetries: (0, common_1.round)(settings.maxRetries),
|
|
1202
|
+
retryDelayMs: (0, common_1.round)(settings.retryDelayMs),
|
|
1203
|
+
responseFormat: 'json'
|
|
1204
|
+
});
|
|
1205
|
+
return [4 /*yield*/, client.chat([
|
|
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
|
+
timeoutMs: (0, common_1.round)(settings.timeoutMs),
|
|
1219
|
+
responseFormat: 'json'
|
|
1220
|
+
})];
|
|
1221
|
+
case 3:
|
|
1222
|
+
response = _c.sent();
|
|
1223
|
+
parsed = parseAiPlanPayload(response.content);
|
|
1224
|
+
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
|
+
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
|
+
if (!collection) {
|
|
1227
|
+
throw new Error('Mongo Explorer AI assistant could not resolve a collection.');
|
|
1228
|
+
}
|
|
1229
|
+
plan = {
|
|
1230
|
+
action: action,
|
|
1231
|
+
collection: collection,
|
|
1232
|
+
options: {}
|
|
1233
|
+
};
|
|
1234
|
+
removedRestrictedStages = false;
|
|
1235
|
+
if (!(action === 'aggregate')) return [3 /*break*/, 5];
|
|
1236
|
+
optionsRaw = normalizeAiObject(parsed === null || parsed === void 0 ? void 0 : parsed.options);
|
|
1237
|
+
aggregateLimit = normalizeAiResultLimit((_b = optionsRaw.limit) !== null && _b !== void 0 ? _b : parsed === null || parsed === void 0 ? void 0 : parsed.limit, maxResults);
|
|
1238
|
+
pipelineResult = sanitizeAggregatePipeline(parsed === null || parsed === void 0 ? void 0 : parsed.pipeline, aggregateLimit);
|
|
1239
|
+
removedRestrictedStages = pipelineResult.removedRestricted;
|
|
1240
|
+
aggregateOptions = {
|
|
1241
|
+
allowDiskUse: optionsRaw.allowDiskUse === true
|
|
1242
|
+
};
|
|
1243
|
+
return [4 /*yield*/, db.collection(collection).aggregate(pipelineResult.pipeline, aggregateOptions).toArray()];
|
|
1244
|
+
case 4:
|
|
1245
|
+
aggregateRows = _c.sent();
|
|
1246
|
+
rows = (aggregateRows || []).slice(0, aggregateLimit);
|
|
1247
|
+
plan = {
|
|
1248
|
+
action: action,
|
|
1249
|
+
collection: collection,
|
|
1250
|
+
pipeline: pipelineResult.pipeline,
|
|
1251
|
+
options: {
|
|
1252
|
+
allowDiskUse: aggregateOptions.allowDiskUse,
|
|
1253
|
+
limit: aggregateLimit
|
|
1254
|
+
},
|
|
1255
|
+
documents: rows,
|
|
1256
|
+
total: null
|
|
1257
|
+
};
|
|
1258
|
+
return [3 /*break*/, 10];
|
|
1259
|
+
case 5:
|
|
1260
|
+
query = normalizeAiObject(parsed === null || parsed === void 0 ? void 0 : parsed.query);
|
|
1261
|
+
options = sanitizeFindOptions(parsed === null || parsed === void 0 ? void 0 : parsed.options, maxResults);
|
|
1262
|
+
findOptions = {
|
|
1263
|
+
limit: options.limit,
|
|
1264
|
+
skip: options.skip
|
|
1265
|
+
};
|
|
1266
|
+
if (options.projection) {
|
|
1267
|
+
findOptions.projection = options.projection;
|
|
1268
|
+
}
|
|
1269
|
+
if (options.sort) {
|
|
1270
|
+
findOptions.sort = options.sort;
|
|
1271
|
+
}
|
|
1272
|
+
return [4 /*yield*/, db.collection(collection).find(query, findOptions).toArray()];
|
|
1273
|
+
case 6:
|
|
1274
|
+
rows = _c.sent();
|
|
1275
|
+
if (!options.includeTotal) return [3 /*break*/, 8];
|
|
1276
|
+
return [4 /*yield*/, db.collection(collection).countDocuments(query)];
|
|
1277
|
+
case 7:
|
|
1278
|
+
_a = _c.sent();
|
|
1279
|
+
return [3 /*break*/, 9];
|
|
1280
|
+
case 8:
|
|
1281
|
+
_a = null;
|
|
1282
|
+
_c.label = 9;
|
|
1283
|
+
case 9:
|
|
1284
|
+
total = _a;
|
|
1285
|
+
plan = {
|
|
1286
|
+
action: action,
|
|
1287
|
+
collection: collection,
|
|
1288
|
+
query: query,
|
|
1289
|
+
options: __assign(__assign(__assign({}, (options.projection ? { projection: options.projection } : {})), (options.sort ? { sort: options.sort } : {})), { limit: options.limit, skip: options.skip, includeTotal: options.includeTotal }),
|
|
1290
|
+
documents: rows,
|
|
1291
|
+
total: total
|
|
1292
|
+
};
|
|
1293
|
+
_c.label = 10;
|
|
1294
|
+
case 10:
|
|
1295
|
+
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 = response.usage || { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
1297
|
+
return [4 /*yield*/, resolveUsageClientId(input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
|
|
1298
|
+
case 11:
|
|
1299
|
+
idClient = _c.sent();
|
|
1300
|
+
if (!(idClient && usage.totalTokens)) return [3 /*break*/, 13];
|
|
1301
|
+
return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
|
|
1302
|
+
id_client: idClient,
|
|
1303
|
+
model: response.model || settings.model || 'unknown',
|
|
1304
|
+
input_tokens: usage.inputTokens || 0,
|
|
1305
|
+
output_tokens: usage.outputTokens || 0,
|
|
1306
|
+
total_tokens: usage.totalTokens || 0,
|
|
1307
|
+
category: 'mongo-explorer-ai',
|
|
1308
|
+
id_request: response.requestId || ''
|
|
1309
|
+
})];
|
|
1310
|
+
case 12:
|
|
1311
|
+
_c.sent();
|
|
1312
|
+
_c.label = 13;
|
|
1313
|
+
case 13: return [2 /*return*/, {
|
|
1314
|
+
notes: plan.notes,
|
|
1315
|
+
plan: plan,
|
|
1316
|
+
model: response.model || settings.model,
|
|
1317
|
+
usage: {
|
|
1318
|
+
input_tokens: usage.inputTokens || 0,
|
|
1319
|
+
output_tokens: usage.outputTokens || 0,
|
|
1320
|
+
total_tokens: usage.totalTokens || 0
|
|
1321
|
+
}
|
|
1322
|
+
}];
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
851
1327
|
function loadMongoExplorerMethods(methodManager) {
|
|
852
1328
|
methodManager.methods({
|
|
1329
|
+
mongoExplorerAiSuggest: {
|
|
1330
|
+
check: new simpl_schema_1.default({
|
|
1331
|
+
payload: {
|
|
1332
|
+
type: Object,
|
|
1333
|
+
blackbox: true
|
|
1334
|
+
}
|
|
1335
|
+
}),
|
|
1336
|
+
function: function (payload) {
|
|
1337
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1338
|
+
return __generator(this, function (_a) {
|
|
1339
|
+
return [2 /*return*/, executeMongoExplorerAi(payload || {}, this)];
|
|
1340
|
+
});
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
853
1344
|
mongoExplorerListCollections: {
|
|
854
1345
|
check: new simpl_schema_1.default({
|
|
855
1346
|
database: {
|