@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.
@@ -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: {