@resolveio/server-lib 22.1.32 → 22.2.1

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.
@@ -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 openai_client_1 = require("../services/openai-client");
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$/;
@@ -729,7 +730,7 @@ function normalizeRiskReview(operation, payload, model, requestId) {
729
730
  ? Math.max(0, Math.min(1, normalizedConfidence))
730
731
  : 0.6;
731
732
  var summary = normalizeOptionalString(payload === null || payload === void 0 ? void 0 : payload.summary)
732
- || "Codex review marked this operation as ".concat(riskLevel, " risk.");
733
+ || "AI review marked this operation as ".concat(riskLevel, " risk.");
733
734
  var reasons = normalizeRiskList(payload === null || payload === void 0 ? void 0 : payload.reasons);
734
735
  var suggestedChecks = normalizeRiskList(payload === null || payload === void 0 ? void 0 : payload.suggested_checks);
735
736
  var shouldBlock = (payload === null || payload === void 0 ? void 0 : payload.should_block) === true || riskLevel === 'critical';
@@ -756,9 +757,7 @@ function resolveRiskReviewSettings() {
756
757
  || serverConfig['AI_ASSISTANT_CODEX_MODEL']
757
758
  || process.env.AI_ASSISTANT_CODEX_MODEL
758
759
  || serverConfig['AI_DASHBOARD_CODEX_MODEL']
759
- || process.env.AI_DASHBOARD_CODEX_MODEL
760
- || serverConfig['OPENAI_MODEL']
761
- || process.env.OPENAI_MODEL) || DEFAULT_RISK_REVIEW_MODEL;
760
+ || process.env.AI_DASHBOARD_CODEX_MODEL) || DEFAULT_RISK_REVIEW_MODEL;
762
761
  var fallbackModel = normalizeOptionalString(serverConfig['MONGO_EXPLORER_RISK_REVIEW_FALLBACK_MODEL']
763
762
  || process.env.MONGO_EXPLORER_RISK_REVIEW_FALLBACK_MODEL
764
763
  || serverConfig['AI_ASSISTANT_CODEX_FALLBACK_MODEL']
@@ -783,6 +782,26 @@ function resolveRiskReviewSettings() {
783
782
  retryDelayMs: retryDelayMs
784
783
  };
785
784
  }
785
+ function buildCodexPrompt(systemPrompt, userPrompt) {
786
+ return "System:\n".concat(systemPrompt, "\n\nUser:\n").concat(userPrompt).trim();
787
+ }
788
+ function buildCodexClient(settings) {
789
+ var fallbackModels = [];
790
+ var fallback = normalizeOptionalString(settings.fallbackModel);
791
+ if (fallback && fallback !== settings.model) {
792
+ fallbackModels.push(fallback);
793
+ }
794
+ 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) }));
795
+ }
796
+ function estimateCodexUsage(messages, responseText, model) {
797
+ var inputTokens = (0, tokenizer_1.countChatTokens)(messages, model);
798
+ var outputTokens = (0, tokenizer_1.countTokens)(responseText || '', model);
799
+ return {
800
+ inputTokens: inputTokens,
801
+ outputTokens: outputTokens,
802
+ totalTokens: inputTokens + outputTokens
803
+ };
804
+ }
786
805
  function buildRiskReviewPrompt(input) {
787
806
  var payload = {
788
807
  database: input.database,
@@ -803,7 +822,7 @@ function buildRiskReviewPrompt(input) {
803
822
  }
804
823
  function reviewOperationRisk(input) {
805
824
  return __awaiter(this, void 0, void 0, function () {
806
- var settings, client, systemPrompt, response, payload, err_1, detail;
825
+ var settings, client, systemPrompt, userPrompt, prompt, responseText, payload, err_1, detail;
807
826
  return __generator(this, function (_a) {
808
827
  switch (_a.label) {
809
828
  case 0:
@@ -812,19 +831,9 @@ function reviewOperationRisk(input) {
812
831
  return [2 /*return*/, buildDisabledRiskReview(input.operation)];
813
832
  }
814
833
  if (!settings.apiKey) {
815
- return [2 /*return*/, buildFallbackRiskReview(input.operation, 'AI risk review unavailable: OPENAI_API_KEY is missing.')];
834
+ return [2 /*return*/, buildFallbackRiskReview(input.operation, 'AI risk review unavailable: AI API key is missing.')];
816
835
  }
817
- client = new openai_client_1.OpenAIClient({
818
- apiKey: settings.apiKey,
819
- baseUrl: settings.baseUrl,
820
- model: settings.model,
821
- fallbackModel: settings.fallbackModel,
822
- temperature: 0.1,
823
- maxTokens: settings.maxTokens,
824
- maxRetries: (0, common_1.round)(settings.maxRetries),
825
- retryDelayMs: (0, common_1.round)(settings.retryDelayMs),
826
- responseFormat: 'json'
827
- });
836
+ client = buildCodexClient(settings);
828
837
  systemPrompt = [
829
838
  'You are a MongoDB operation safety reviewer for a production SaaS application.',
830
839
  'Respond with a single JSON object only.',
@@ -837,20 +846,27 @@ function reviewOperationRisk(input) {
837
846
  'confidence (number between 0 and 1).',
838
847
  'Keep summary concise (<= 220 chars).'
839
848
  ].join(' ');
849
+ userPrompt = buildRiskReviewPrompt(input);
850
+ prompt = buildCodexPrompt(systemPrompt, userPrompt);
840
851
  _a.label = 1;
841
852
  case 1:
842
853
  _a.trys.push([1, 3, , 4]);
843
- return [4 /*yield*/, client.chat([
844
- { role: 'system', content: systemPrompt },
845
- { role: 'user', content: buildRiskReviewPrompt(input) }
846
- ], {
854
+ return [4 /*yield*/, client.run(prompt, {
847
855
  timeoutMs: (0, common_1.round)(settings.timeoutMs),
848
- responseFormat: 'json'
856
+ threadOptions: {
857
+ model: settings.model,
858
+ sandboxMode: 'read-only',
859
+ skipGitRepoCheck: true,
860
+ networkAccessEnabled: false,
861
+ webSearchMode: 'disabled',
862
+ webSearchEnabled: false,
863
+ approvalPolicy: 'never'
864
+ }
849
865
  })];
850
866
  case 2:
851
- response = _a.sent();
852
- payload = parseRiskReviewPayload(response.content);
853
- return [2 /*return*/, normalizeRiskReview(input.operation, payload, response.model || settings.model, response.requestId || '')];
867
+ responseText = _a.sent();
868
+ payload = parseRiskReviewPayload(responseText);
869
+ return [2 /*return*/, normalizeRiskReview(input.operation, payload, settings.model, '')];
854
870
  case 3:
855
871
  err_1 = _a.sent();
856
872
  detail = (err_1 === null || err_1 === void 0 ? void 0 : err_1.message) ? String(err_1.message) : 'Unknown AI review error';
@@ -996,9 +1012,7 @@ function resolveMongoExplorerAiSettings() {
996
1012
  var model = normalizeOptionalString(serverConfig['MONGO_EXPLORER_AI_MODEL']
997
1013
  || process.env.MONGO_EXPLORER_AI_MODEL
998
1014
  || serverConfig['AI_ASSISTANT_CODEX_MODEL']
999
- || process.env.AI_ASSISTANT_CODEX_MODEL
1000
- || serverConfig['OPENAI_MODEL']
1001
- || process.env.OPENAI_MODEL) || DEFAULT_AI_SUGGEST_MODEL;
1015
+ || process.env.AI_ASSISTANT_CODEX_MODEL) || DEFAULT_AI_SUGGEST_MODEL;
1002
1016
  var fallbackModel = normalizeOptionalString(serverConfig['MONGO_EXPLORER_AI_FALLBACK_MODEL']
1003
1017
  || process.env.MONGO_EXPLORER_AI_FALLBACK_MODEL
1004
1018
  || serverConfig['AI_ASSISTANT_CODEX_FALLBACK_MODEL']
@@ -1147,7 +1161,7 @@ function resolveUsageClientId(idClientInput, idUser) {
1147
1161
  }
1148
1162
  function executeMongoExplorerAi(payload, context) {
1149
1163
  return __awaiter(this, void 0, void 0, function () {
1150
- 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;
1164
+ 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;
1151
1165
  var _b;
1152
1166
  return __generator(this, function (_c) {
1153
1167
  switch (_c.label) {
@@ -1180,39 +1194,38 @@ function executeMongoExplorerAi(payload, context) {
1180
1194
  }
1181
1195
  settings = resolveMongoExplorerAiSettings();
1182
1196
  if (!settings.apiKey) {
1183
- throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
1197
+ throw new Error('AI API key missing. Add an AI API key to server config.');
1184
1198
  }
1185
1199
  maxResults = normalizeAiResultLimit(input.max_results, 100);
1186
- client = new openai_client_1.OpenAIClient({
1187
- apiKey: settings.apiKey,
1188
- baseUrl: settings.baseUrl,
1189
- model: settings.model,
1190
- fallbackModel: settings.fallbackModel,
1191
- temperature: 0.1,
1192
- maxTokens: (0, common_1.round)(settings.maxTokens),
1193
- maxRetries: (0, common_1.round)(settings.maxRetries),
1194
- retryDelayMs: (0, common_1.round)(settings.retryDelayMs),
1195
- responseFormat: 'json'
1196
- });
1197
- return [4 /*yield*/, client.chat([
1198
- { role: 'system', content: buildMongoExplorerAiSystemPrompt() },
1199
- {
1200
- role: 'user',
1201
- content: buildMongoExplorerAiUserPrompt({
1202
- prompt: prompt,
1203
- selectedCollection: selectedCollection,
1204
- availableCollections: availableCollections,
1205
- availableFields: availableFields,
1206
- maxResults: maxResults
1207
- })
1208
- }
1209
- ], {
1200
+ client = buildCodexClient(settings);
1201
+ messages = [
1202
+ { role: 'system', content: buildMongoExplorerAiSystemPrompt() },
1203
+ {
1204
+ role: 'user',
1205
+ content: buildMongoExplorerAiUserPrompt({
1206
+ prompt: prompt,
1207
+ selectedCollection: selectedCollection,
1208
+ availableCollections: availableCollections,
1209
+ availableFields: availableFields,
1210
+ maxResults: maxResults
1211
+ })
1212
+ }
1213
+ ];
1214
+ return [4 /*yield*/, client.run(buildCodexPrompt(messages[0].content, messages[1].content), {
1210
1215
  timeoutMs: (0, common_1.round)(settings.timeoutMs),
1211
- responseFormat: 'json'
1216
+ threadOptions: {
1217
+ model: settings.model,
1218
+ sandboxMode: 'read-only',
1219
+ skipGitRepoCheck: true,
1220
+ networkAccessEnabled: false,
1221
+ webSearchMode: 'disabled',
1222
+ webSearchEnabled: false,
1223
+ approvalPolicy: 'never'
1224
+ }
1212
1225
  })];
1213
1226
  case 3:
1214
- response = _c.sent();
1215
- parsed = parseAiPlanPayload(response.content);
1227
+ responseText = _c.sent();
1228
+ parsed = parseAiPlanPayload(responseText);
1216
1229
  action = normalizeAiAction((parsed === null || parsed === void 0 ? void 0 : parsed.action) || (Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.pipeline) ? 'aggregate' : 'find'));
1217
1230
  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]);
1218
1231
  if (!collection) {
@@ -1285,19 +1298,19 @@ function executeMongoExplorerAi(payload, context) {
1285
1298
  _c.label = 10;
1286
1299
  case 10:
1287
1300
  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);
1288
- usage = response.usage || { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1301
+ usage = estimateCodexUsage(messages, responseText, settings.model);
1289
1302
  return [4 /*yield*/, resolveUsageClientId(input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1290
1303
  case 11:
1291
1304
  idClient = _c.sent();
1292
1305
  if (!(idClient && usage.totalTokens)) return [3 /*break*/, 13];
1293
1306
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1294
1307
  id_client: idClient,
1295
- model: response.model || settings.model || 'unknown',
1308
+ model: settings.model || 'unknown',
1296
1309
  input_tokens: usage.inputTokens || 0,
1297
1310
  output_tokens: usage.outputTokens || 0,
1298
1311
  total_tokens: usage.totalTokens || 0,
1299
1312
  category: 'mongo-explorer-ai',
1300
- id_request: response.requestId || ''
1313
+ id_request: ''
1301
1314
  })];
1302
1315
  case 12:
1303
1316
  _c.sent();
@@ -1305,7 +1318,7 @@ function executeMongoExplorerAi(payload, context) {
1305
1318
  case 13: return [2 /*return*/, {
1306
1319
  notes: plan.notes,
1307
1320
  plan: plan,
1308
- model: response.model || settings.model,
1321
+ model: settings.model,
1309
1322
  usage: {
1310
1323
  input_tokens: usage.inputTokens || 0,
1311
1324
  output_tokens: usage.outputTokens || 0,