@resolveio/server-lib 20.15.3 → 20.15.5

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.
@@ -133,7 +133,7 @@ var DEFAULT_MAX_FILE_MB = 50;
133
133
  var DEFAULT_MAX_TOTAL_MB = 100;
134
134
  var DEFAULT_MAX_ATTACHMENT_CHARS = 12000;
135
135
  var DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS = 40000;
136
- var DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
136
+ var DEFAULT_CODEX_MODEL = 'gpt-5.1-codex-mini';
137
137
  var DEFAULT_CODEX_TIMEOUT_MS = 180000;
138
138
  var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
139
139
  var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
@@ -144,6 +144,7 @@ var AI_ASSISTANT_DISPLAY_PREVIEW_MAX_ROWS = 20;
144
144
  var AI_ASSISTANT_DISPLAY_STRING_LIMIT = 160;
145
145
  var AI_ASSISTANT_PROGRESS_PLACEHOLDER = 'Thinking...';
146
146
  var AI_ASSISTANT_PROGRESS_TICK_MS = 5000;
147
+ var AI_ASSISTANT_READ_PREFERENCE = 'secondary';
147
148
  var AI_ASSISTANT_PROGRESS_TICKS = [
148
149
  'Drafting response'
149
150
  ];
@@ -199,6 +200,51 @@ var AI_ASSISTANT_SENSITIVE_FIELDS = [
199
200
  'roles'
200
201
  ];
201
202
  var AI_ASSISTANT_CLIENT_SCOPE_CACHE = new Map();
203
+ var AI_ASSISTANT_COLLECTION_CACHE = new Map();
204
+ var AI_ASSISTANT_COLLECTION_CACHE_TTL_MS = 5 * 60 * 1000;
205
+ var AI_ASSISTANT_COLLECTION_STOPWORDS = new Set([
206
+ 'the',
207
+ 'a',
208
+ 'an',
209
+ 'of',
210
+ 'for',
211
+ 'by',
212
+ 'with',
213
+ 'and',
214
+ 'or',
215
+ 'to',
216
+ 'from',
217
+ 'in',
218
+ 'on',
219
+ 'at',
220
+ 'last',
221
+ 'recent',
222
+ 'today',
223
+ 'week',
224
+ 'month',
225
+ 'year',
226
+ 'this',
227
+ 'that',
228
+ 'these',
229
+ 'those',
230
+ 'show',
231
+ 'list',
232
+ 'get',
233
+ 'give',
234
+ 'how',
235
+ 'many',
236
+ 'count',
237
+ 'total',
238
+ 'breakdown',
239
+ 'group',
240
+ 'grouped',
241
+ 'per',
242
+ 'open',
243
+ 'closed',
244
+ 'completed',
245
+ 'missing',
246
+ 'overdue'
247
+ ]);
202
248
  var AI_ASSISTANT_SYSTEM_PROMPT = [
203
249
  'You are the ResolveIO in-app AI assistant running with read-only access to the codebase.',
204
250
  'Core rules:',
@@ -209,11 +255,16 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
209
255
  '- If the user has a customer portal scope (other.id_customer), only discuss that customer\'s data and what is visible in their customer portal. Never reference other customers or internal/admin-only data. If asked for anything outside the portal, say it isn\'t available.',
210
256
  '- Do not assist with hacking, bypassing security, or abuse.',
211
257
  'Accuracy & tools:',
258
+ '- Step 1 (always): determine the target collections/models/modules/workflows using context, routes, and collection hints. Assume the user is non-technical and will not provide internal names.',
259
+ '- Map user wording to internal collections/fields yourself. Do not ask for property names unless required to run a query.',
212
260
  '- Do not guess or invent collections/fields. If unsure, verify in the codebase or run a small Mongo read (limit 1-5) to learn the shape.',
213
261
  '- Prefer running a small Mongo read over asking multiple questions.',
262
+ '- For any data request (counts, lists, breakdowns, recent/last items), you MUST run a MONGO_READ or MONGO_AGG before answering.',
214
263
  '- Ask at most one clarifying question only when required to run a query or resolve missing details.',
215
264
  '- If a field starts with id_ and refers to another collection, treat it as a foreign key and look up the related record when needed.',
265
+ '- When the user provides a customer, well, or chemical name, use case-insensitive regex matching to find it. Assume the name exists and try to match it before asking questions.',
216
266
  '- Use the codebase context to choose correct collections/fields/workflows and use MONGO_READ/MONGO_AGG to answer with real data when needed.',
267
+ '- Assume a relevant collection exists; if verification reads return zero data, report no data found instead of interrogating the user.',
217
268
  '- For direct questions, answer first. Ask a single follow-up only if required to proceed.',
218
269
  'Data Presentation:',
219
270
  '- Output plain Markdown (NO triple backticks).',
@@ -224,6 +275,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
224
275
  '- If `_id` & `__v` & `id_<other collection _id property>` is needed, show it as `id` and shorten (e.g., first 6-8 chars) unless asked otherwise.',
225
276
  '- Rename `createdAt` to `Created At` and `updatedAt` to `Updated At` in tables.',
226
277
  'Response style:',
278
+ '- Respond in English only. Do not include non-English text or characters unless required for JSON, links, or tool directives.',
227
279
  '- Keep responses concise: answer first, then 3-8 bullets, then a table when data is involved.',
228
280
  '- Prefer high-level explanations and point to routes instead of code. Only mention file paths if explicitly requested.',
229
281
  '- When asked where to do something, give the exact screen name and the in-app route as a standalone path starting with "/" so it can be clicked.',
@@ -256,12 +308,14 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
256
308
  '- Only request data when the user has permission for that module; invoice data requires invoice view access.',
257
309
  '- If the user lacks permission, answer without data and explain how to view it in the app or request access.',
258
310
  '- For simple counts or time-range totals, use MONGO_READ (includeTotal). For breakdowns, rankings, or sums grouped by a field, use MONGO_AGG.',
311
+ '- For completion metrics (ex: "completed per day"), filter by completed status when applicable and use completion date fields; if completion dates are missing, fall back to createdAt/date_created and note the fallback.',
259
312
  '- Before issuing MONGO_READ or MONGO_AGG, verify the collection name and key fields by checking collection/model definitions in the current app (look for "collectionName:" and date fields like date_created/date_completed/createdAt). Do not invent collection names.',
260
313
  '- For creation-date questions when both date_created and createdAt exist, match both with $or so results are not missed.',
261
314
  '- When grouping by fields that can be arrays (drivers, deliveries, routes, chemicals), $unwind first and group by both id and name when available.',
262
315
  '- Use MONGO_READ/MONGO_AGG only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
263
316
  '- If the user explicitly asks for IDs, set options.includeIds: true.',
264
- '- Keep responses concise and use low reasoning effort.'
317
+ '- If a data question returns zero results, verify the collection/date field with a tiny read (limit 1-5) or a date field fallback before concluding there is no data.',
318
+ '- Keep responses concise and use the configured reasoning effort level (default low).'
265
319
  ].join('\n');
266
320
  var AI_FORM_PATCH_SYSTEM_PROMPT = [
267
321
  'You are the ResolveIO form patch assistant.',
@@ -800,10 +854,10 @@ function executeAiFormPatch(payload, context) {
800
854
  }
801
855
  function executeAiAssistantCodexRun(payload, context) {
802
856
  return __awaiter(this, void 0, void 0, function () {
803
- var input, message, requestId, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, assistantContext, prompt, workspaceRoot, codexConfig, runOptions, userDoc, initialProgress, assistantDoc, insertResult, assistantMessageId, progressTracker, streamProgress, assistantContent, toolResult, responseText, directive, cleanedResponseText, toolRequest, toolResponse, _b, toolPayload, followupPrompt, followupText, _c, error_1, error_2, finalNow, finalMetadata, finalAssistantDoc;
804
- var _d, _e;
805
- return __generator(this, function (_f) {
806
- switch (_f.label) {
857
+ var input, message, requestId, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, collectionHints, dbName, db, hintText, _b, assistantContext, prompt, workspaceRoot, codexConfig, runOptions, userDoc, initialProgress, assistantDoc, insertResult, assistantMessageId, progressTracker, streamProgress, assistantContent, toolResult, assistantDebug, directiveSource, dataQuestion, lastDirective, toolResponseDebug, toolError, responseText, directive, directiveSourceText, directivePrompt, directiveText, forcedDirective, _c, cleanedResponseText, toolRequest, toolResponse, _d, toolPayload, followupPrompt, followupText, _e, error_1, error_2, finalNow, finalMetadata, finalAssistantDoc;
858
+ var _f, _g, _h;
859
+ return __generator(this, function (_j) {
860
+ switch (_j.label) {
807
861
  case 0:
808
862
  input = payload || {};
809
863
  message = normalizeOptionalString(input.message);
@@ -818,7 +872,7 @@ function executeAiAssistantCodexRun(payload, context) {
818
872
  if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
819
873
  return [4 /*yield*/, ensureConversation(input, 'codex')];
820
874
  case 1:
821
- conversation_2 = _f.sent();
875
+ conversation_2 = _j.sent();
822
876
  now_2 = new Date();
823
877
  userMsg = {
824
878
  id_conversation: conversation_2._id,
@@ -838,13 +892,13 @@ function executeAiAssistantCodexRun(payload, context) {
838
892
  };
839
893
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userMsg)];
840
894
  case 2:
841
- _f.sent();
895
+ _j.sent();
842
896
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantMsg)];
843
897
  case 3:
844
- _f.sent();
898
+ _j.sent();
845
899
  return [4 /*yield*/, touchConversation(conversation_2._id, now_2)];
846
900
  case 4:
847
- _f.sent();
901
+ _j.sent();
848
902
  return [2 /*return*/, {
849
903
  conversation: conversation_2,
850
904
  message: assistantMsg,
@@ -852,27 +906,27 @@ function executeAiAssistantCodexRun(payload, context) {
852
906
  }];
853
907
  case 5: return [4 /*yield*/, user_collection_1.Users.findById(context === null || context === void 0 ? void 0 : context.id_user)];
854
908
  case 6:
855
- user = _f.sent();
856
- isSuperAdmin = !!((_d = user === null || user === void 0 ? void 0 : user.roles) === null || _d === void 0 ? void 0 : _d.super_admin);
909
+ user = _j.sent();
910
+ isSuperAdmin = !!((_f = user === null || user === void 0 ? void 0 : user.roles) === null || _f === void 0 ? void 0 : _f.super_admin);
857
911
  hasInvoiceAccess = userHasInvoiceAccess(user);
858
- customerId = normalizeOptionalString((_e = user === null || user === void 0 ? void 0 : user.other) === null || _e === void 0 ? void 0 : _e.id_customer);
912
+ customerId = normalizeOptionalString((_g = user === null || user === void 0 ? void 0 : user.other) === null || _g === void 0 ? void 0 : _g.id_customer);
859
913
  return [4 /*yield*/, ensureConversation(input, 'codex')];
860
914
  case 7:
861
- conversation = _f.sent();
915
+ conversation = _j.sent();
862
916
  now = new Date();
863
917
  attachments = Array.isArray(input.attachments) ? input.attachments : [];
864
918
  return [4 /*yield*/, readAttachmentContents(attachments)];
865
919
  case 8:
866
- attachmentData = _f.sent();
920
+ attachmentData = _j.sent();
867
921
  historyLimit = normalizeHistoryLimit(input.max_history);
868
922
  if (!(historyLimit > 0)) return [3 /*break*/, 10];
869
923
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find({ id_conversation: conversation._id, role: { $in: ['user', 'assistant'] } }, { sort: { createdAt: 1 }, limit: historyLimit * 2 })];
870
924
  case 9:
871
- _a = _f.sent();
925
+ _a = _j.sent();
872
926
  return [3 /*break*/, 11];
873
927
  case 10:
874
928
  _a = [];
875
- _f.label = 11;
929
+ _j.label = 11;
876
930
  case 11:
877
931
  history = _a;
878
932
  historyLines = [];
@@ -883,11 +937,35 @@ function executeAiAssistantCodexRun(payload, context) {
883
937
  historyLines.push("".concat(role, ": ").concat(content));
884
938
  }
885
939
  });
886
- assistantContext = buildAssistantContext(input, { isSuperAdmin: isSuperAdmin, hasInvoiceAccess: hasInvoiceAccess, customerId: customerId });
940
+ collectionHints = [];
941
+ _j.label = 12;
942
+ case 12:
943
+ _j.trys.push([12, 14, , 15]);
944
+ dbName = resolveAssistantDatabaseName(undefined, input.mongo);
945
+ db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
946
+ hintText = [
947
+ message,
948
+ normalizeOptionalString((_h = input === null || input === void 0 ? void 0 : input.context) === null || _h === void 0 ? void 0 : _h.route)
949
+ ].filter(Boolean).join(' ');
950
+ return [4 /*yield*/, resolveAssistantCollectionHints(hintText, dbName, db)];
951
+ case 13:
952
+ collectionHints = _j.sent();
953
+ return [3 /*break*/, 15];
954
+ case 14:
955
+ _b = _j.sent();
956
+ collectionHints = [];
957
+ return [3 /*break*/, 15];
958
+ case 15:
959
+ assistantContext = buildAssistantContext(input, {
960
+ isSuperAdmin: isSuperAdmin,
961
+ hasInvoiceAccess: hasInvoiceAccess,
962
+ customerId: customerId,
963
+ collectionHints: collectionHints
964
+ });
887
965
  prompt = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
888
966
  return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
889
- case 12:
890
- workspaceRoot = _f.sent();
967
+ case 16:
968
+ workspaceRoot = _j.sent();
891
969
  codexConfig = resolveCodexSettings();
892
970
  runOptions = {
893
971
  timeoutMs: resolveCodexTimeoutMs(),
@@ -895,7 +973,7 @@ function executeAiAssistantCodexRun(payload, context) {
895
973
  workingDirectory: workspaceRoot,
896
974
  sandboxMode: 'read-only',
897
975
  skipGitRepoCheck: true,
898
- modelReasoningEffort: 'low',
976
+ modelReasoningEffort: resolveCodexThoughtLevel(),
899
977
  networkAccessEnabled: false,
900
978
  webSearchMode: 'disabled',
901
979
  webSearchEnabled: false,
@@ -921,83 +999,128 @@ function executeAiAssistantCodexRun(payload, context) {
921
999
  updatedAt: now
922
1000
  };
923
1001
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
924
- case 13:
925
- _f.sent();
1002
+ case 17:
1003
+ _j.sent();
926
1004
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
927
- case 14:
928
- insertResult = _f.sent();
1005
+ case 18:
1006
+ insertResult = _j.sent();
929
1007
  assistantMessageId = (insertResult === null || insertResult === void 0 ? void 0 : insertResult._id) || (insertResult === null || insertResult === void 0 ? void 0 : insertResult.insertedId);
930
1008
  progressTracker = createAssistantProgressTracker(assistantMessageId, initialProgress);
931
1009
  streamProgress = createAssistantStreamProgressHandler(progressTracker);
932
1010
  assistantContent = '';
933
1011
  toolResult = null;
934
- _f.label = 15;
935
- case 15:
936
- _f.trys.push([15, 30, 31, 32]);
1012
+ assistantDebug = null;
1013
+ directiveSource = 'none';
1014
+ dataQuestion = isAssistantDataQuestion(message);
1015
+ lastDirective = null;
1016
+ toolResponseDebug = null;
1017
+ toolError = null;
1018
+ _j.label = 19;
1019
+ case 19:
1020
+ _j.trys.push([19, 38, 39, 40]);
937
1021
  return [4 /*yield*/, runCodexInWorkerThread(prompt, runOptions, codexConfig, streamProgress)];
938
- case 16:
939
- responseText = _f.sent();
1022
+ case 20:
1023
+ responseText = _j.sent();
940
1024
  directive = extractAssistantMongoDirective(responseText);
941
- cleanedResponseText = (directive === null || directive === void 0 ? void 0 : directive.cleaned) || responseText;
1025
+ directiveSourceText = responseText;
1026
+ if (directive) {
1027
+ directiveSource = 'model';
1028
+ lastDirective = directive;
1029
+ }
1030
+ if (!(!directive && dataQuestion)) return [3 /*break*/, 24];
1031
+ directivePrompt = buildAssistantCodexDirectivePrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
1032
+ _j.label = 21;
1033
+ case 21:
1034
+ _j.trys.push([21, 23, , 24]);
1035
+ return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, runOptions, codexConfig, streamProgress)];
1036
+ case 22:
1037
+ directiveText = _j.sent();
1038
+ forcedDirective = extractAssistantMongoDirective(directiveText);
1039
+ if (forcedDirective) {
1040
+ directive = forcedDirective;
1041
+ directiveSourceText = directiveText;
1042
+ directiveSource = 'forced';
1043
+ lastDirective = forcedDirective;
1044
+ }
1045
+ return [3 /*break*/, 24];
1046
+ case 23:
1047
+ _c = _j.sent();
1048
+ return [3 /*break*/, 24];
1049
+ case 24:
1050
+ cleanedResponseText = (directive === null || directive === void 0 ? void 0 : directive.cleaned) || directiveSourceText;
942
1051
  assistantContent = sanitizeAssistantResponse(cleanedResponseText);
943
- if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 28];
1052
+ if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 36];
944
1053
  toolRequest = buildAssistantToolRequest(directive, input);
945
1054
  progressTracker.push('Looking up Data');
946
- _f.label = 17;
947
- case 17:
948
- _f.trys.push([17, 26, , 27]);
949
- if (!(directive.type === 'aggregate')) return [3 /*break*/, 19];
1055
+ _j.label = 25;
1056
+ case 25:
1057
+ _j.trys.push([25, 34, , 35]);
1058
+ if (!(directive.type === 'aggregate')) return [3 /*break*/, 27];
950
1059
  return [4 /*yield*/, executeAiAssistantMongoAggregate(toolRequest, context)];
951
- case 18:
952
- _b = _f.sent();
953
- return [3 /*break*/, 21];
954
- case 19: return [4 /*yield*/, executeAiAssistantMongoRead(toolRequest, context)];
955
- case 20:
956
- _b = _f.sent();
957
- _f.label = 21;
958
- case 21:
959
- toolResponse = _b;
1060
+ case 26:
1061
+ _d = _j.sent();
1062
+ return [3 /*break*/, 29];
1063
+ case 27: return [4 /*yield*/, executeAiAssistantMongoRead(toolRequest, context)];
1064
+ case 28:
1065
+ _d = _j.sent();
1066
+ _j.label = 29;
1067
+ case 29:
1068
+ toolResponse = _d;
1069
+ toolResponseDebug = (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) && typeof toolResponse.debug === 'object'
1070
+ ? toolResponse.debug
1071
+ : null;
960
1072
  toolPayload = buildAssistantToolResultPayload(directive, toolResponse);
961
1073
  toolResult = toolPayload.result;
962
1074
  progressTracker.push('Drafting response');
963
1075
  followupPrompt = buildAssistantCodexToolFollowupPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, toolPayload.prompt);
964
- _f.label = 22;
965
- case 22:
966
- _f.trys.push([22, 24, , 25]);
1076
+ _j.label = 30;
1077
+ case 30:
1078
+ _j.trys.push([30, 32, , 33]);
967
1079
  return [4 /*yield*/, runCodexInWorkerThread(followupPrompt, runOptions, codexConfig, streamProgress)];
968
- case 23:
969
- followupText = _f.sent();
1080
+ case 31:
1081
+ followupText = _j.sent();
970
1082
  assistantContent = sanitizeAssistantResponse(followupText);
971
- return [3 /*break*/, 25];
972
- case 24:
973
- _c = _f.sent();
1083
+ return [3 /*break*/, 33];
1084
+ case 32:
1085
+ _e = _j.sent();
974
1086
  assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
975
- return [3 /*break*/, 25];
976
- case 25: return [3 /*break*/, 27];
977
- case 26:
978
- error_1 = _f.sent();
1087
+ return [3 /*break*/, 33];
1088
+ case 33: return [3 /*break*/, 35];
1089
+ case 34:
1090
+ error_1 = _j.sent();
979
1091
  assistantContent = buildAssistantToolErrorMessage(error_1, directive, toolRequest);
980
- return [3 /*break*/, 27];
981
- case 27: return [3 /*break*/, 29];
982
- case 28:
1092
+ toolError = error_1;
1093
+ return [3 /*break*/, 35];
1094
+ case 35: return [3 /*break*/, 37];
1095
+ case 36:
983
1096
  progressTracker.push('Drafting response');
984
- _f.label = 29;
985
- case 29: return [3 /*break*/, 32];
986
- case 30:
987
- error_2 = _f.sent();
1097
+ _j.label = 37;
1098
+ case 37: return [3 /*break*/, 40];
1099
+ case 38:
1100
+ error_2 = _j.sent();
988
1101
  assistantContent = buildAssistantCodexErrorMessage(error_2);
989
- return [3 /*break*/, 32];
990
- case 31:
1102
+ return [3 /*break*/, 40];
1103
+ case 39:
991
1104
  progressTracker.stop();
992
1105
  return [7 /*endfinally*/];
993
- case 32:
1106
+ case 40:
994
1107
  if (!assistantContent) {
995
1108
  assistantContent = buildAssistantCodexErrorMessage(null);
996
1109
  }
997
1110
  finalNow = new Date();
998
- finalMetadata = __assign(__assign({ model: resolveCodexModel() }, (requestId ? { request_id: requestId } : {})), (toolResult ? { tool_result: toolResult } : {}));
1111
+ if (isSuperAdmin) {
1112
+ assistantDebug = buildAssistantDebugPayload({
1113
+ dataQuestion: dataQuestion,
1114
+ directive: lastDirective,
1115
+ directiveSource: directiveSource,
1116
+ toolResult: toolResult,
1117
+ toolResponseDebug: toolResponseDebug,
1118
+ toolError: toolError
1119
+ });
1120
+ }
1121
+ finalMetadata = __assign(__assign(__assign({ model: resolveCodexModel() }, (requestId ? { request_id: requestId } : {})), (toolResult ? { tool_result: toolResult } : {})), (assistantDebug ? { debug: assistantDebug } : {}));
999
1122
  finalAssistantDoc = __assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata, updatedAt: finalNow });
1000
- if (!assistantMessageId) return [3 /*break*/, 34];
1123
+ if (!assistantMessageId) return [3 /*break*/, 42];
1001
1124
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: assistantMessageId }, {
1002
1125
  $set: {
1003
1126
  content: assistantContent,
@@ -1005,43 +1128,47 @@ function executeAiAssistantCodexRun(payload, context) {
1005
1128
  updatedAt: finalNow
1006
1129
  }
1007
1130
  })];
1008
- case 33:
1009
- _f.sent();
1010
- _f.label = 34;
1011
- case 34: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
1012
- case 35:
1013
- _f.sent();
1014
- if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 37];
1131
+ case 41:
1132
+ _j.sent();
1133
+ _j.label = 42;
1134
+ case 42: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
1135
+ case 43:
1136
+ _j.sent();
1137
+ if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 45];
1015
1138
  return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
1016
- case 36:
1017
- _f.sent();
1018
- _f.label = 37;
1019
- case 37: return [2 /*return*/, __assign({ conversation: conversation, message: finalAssistantDoc }, (toolResult ? { tool_result: toolResult } : {}))];
1139
+ case 44:
1140
+ _j.sent();
1141
+ _j.label = 45;
1142
+ case 45: return [2 /*return*/, __assign({ conversation: conversation, message: finalAssistantDoc }, (toolResult ? { tool_result: toolResult } : {}))];
1020
1143
  }
1021
1144
  });
1022
1145
  });
1023
1146
  }
1024
1147
  function executeAiAssistantMongoRead(payload, context) {
1025
1148
  return __awaiter(this, void 0, void 0, function () {
1026
- var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalized, documents, total, sanitizedDocuments, includeIds, display;
1149
+ var input, rawCollection, dbName, db, collectionResolution, collection, _a, user, isSuperAdmin, customerId, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalized, findOptions, documents, executedQuery, fallbackMeta, dateFallback, fallbackQuery, fallbackDocs, total, sanitizedDocuments, includeIds, display;
1027
1150
  var _c, _d;
1028
1151
  return __generator(this, function (_e) {
1029
1152
  switch (_e.label) {
1030
1153
  case 0:
1031
1154
  input = payload || {};
1032
- collection = normalizeOptionalString(input.collection);
1033
- if (!collection) {
1155
+ rawCollection = normalizeOptionalString(input.collection);
1156
+ if (!rawCollection) {
1034
1157
  throw new Error('AI assistant mongo read: Collection is required.');
1035
1158
  }
1036
- return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
1159
+ dbName = resolveAssistantDatabaseName(input.database, input.mongo);
1160
+ db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
1161
+ return [4 /*yield*/, resolveAssistantCollectionName(db, dbName, rawCollection)];
1037
1162
  case 1:
1163
+ collectionResolution = _e.sent();
1164
+ collection = collectionResolution.name || rawCollection;
1165
+ return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
1166
+ case 2:
1038
1167
  _a = _e.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
1039
1168
  if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
1040
1169
  throw new Error('AI assistant mongo read: Access denied.');
1041
1170
  }
1042
1171
  customerId = normalizeOptionalString((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.id_customer);
1043
- dbName = resolveAssistantDatabaseName(input.database, input.mongo);
1044
- db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
1045
1172
  baseQuery = normalizeMongoQuery(input.query);
1046
1173
  if (!isSuperAdmin && (collection === 'users' || collection === 'user-versions')) {
1047
1174
  userId = normalizeOptionalString(user === null || user === void 0 ? void 0 : user._id);
@@ -1053,31 +1180,49 @@ function executeAiAssistantMongoRead(payload, context) {
1053
1180
  };
1054
1181
  }
1055
1182
  normalizedClient = normalizeOptionalString(input.id_client);
1056
- if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
1183
+ if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 4];
1057
1184
  return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
1058
- case 2:
1059
- _b = _e.sent();
1060
- return [3 /*break*/, 4];
1061
1185
  case 3:
1062
- _b = false;
1063
- _e.label = 4;
1186
+ _b = _e.sent();
1187
+ return [3 /*break*/, 5];
1064
1188
  case 4:
1189
+ _b = false;
1190
+ _e.label = 5;
1191
+ case 5:
1065
1192
  shouldScopeByClient = _b;
1066
1193
  clientScopedQuery = shouldScopeByClient
1067
1194
  ? applyClientScopeFilter(baseQuery, normalizedClient, isSuperAdmin)
1068
1195
  : baseQuery;
1069
1196
  scopedQuery = applyCustomerScopeFilter(clientScopedQuery, collection, customerId, isSuperAdmin);
1070
1197
  normalized = normalizeAssistantFindOptions(input.options);
1071
- return [4 /*yield*/, db.collection(collection).find(scopedQuery, normalized.findOptions).toArray()];
1072
- case 5:
1198
+ findOptions = __assign(__assign({}, normalized.findOptions), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
1199
+ return [4 /*yield*/, db.collection(collection).find(scopedQuery, findOptions).toArray()];
1200
+ case 6:
1073
1201
  documents = _e.sent();
1202
+ executedQuery = scopedQuery;
1203
+ fallbackMeta = {};
1204
+ if (!!documents.length) return [3 /*break*/, 8];
1205
+ dateFallback = resolveQueryDateFieldFallback(scopedQuery);
1206
+ if (!dateFallback) return [3 /*break*/, 8];
1207
+ fallbackQuery = replaceQueryField(scopedQuery, dateFallback.from, dateFallback.to);
1208
+ fallbackMeta.dateField = __assign(__assign({}, dateFallback), { attempted: true, used: false });
1209
+ return [4 /*yield*/, db.collection(collection).find(fallbackQuery, findOptions).toArray()];
1210
+ case 7:
1211
+ fallbackDocs = _e.sent();
1212
+ if (fallbackDocs.length) {
1213
+ documents = fallbackDocs;
1214
+ executedQuery = fallbackQuery;
1215
+ fallbackMeta.dateField.used = true;
1216
+ }
1217
+ _e.label = 8;
1218
+ case 8:
1074
1219
  total = null;
1075
- if (!normalized.includeTotal) return [3 /*break*/, 7];
1076
- return [4 /*yield*/, db.collection(collection).countDocuments(scopedQuery)];
1077
- case 6:
1220
+ if (!normalized.includeTotal) return [3 /*break*/, 10];
1221
+ return [4 /*yield*/, db.collection(collection).countDocuments(executedQuery, { readPreference: AI_ASSISTANT_READ_PREFERENCE })];
1222
+ case 9:
1078
1223
  total = _e.sent();
1079
- _e.label = 7;
1080
- case 7:
1224
+ _e.label = 10;
1225
+ case 10:
1081
1226
  sanitizedDocuments = isSuperAdmin
1082
1227
  ? documents
1083
1228
  : documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
@@ -1093,10 +1238,16 @@ function executeAiAssistantMongoRead(payload, context) {
1093
1238
  return [2 /*return*/, __assign({ documents: sanitizedDocuments, total: total, display: display }, (isSuperAdmin ? {
1094
1239
  debug: {
1095
1240
  collection: collection,
1241
+ collectionRequested: rawCollection,
1242
+ collectionResolved: collection,
1243
+ collectionMatched: collectionResolution.matched,
1244
+ collectionCandidates: collectionResolution.candidates,
1245
+ collectionScore: collectionResolution.score,
1096
1246
  database: dbName,
1097
- query: scopedQuery,
1247
+ query: executedQuery,
1098
1248
  options: normalized.findOptions,
1099
- includeTotal: normalized.includeTotal
1249
+ includeTotal: normalized.includeTotal,
1250
+ fallbacks: fallbackMeta
1100
1251
  }
1101
1252
  } : {}))];
1102
1253
  }
@@ -1105,25 +1256,29 @@ function executeAiAssistantMongoRead(payload, context) {
1105
1256
  }
1106
1257
  function executeAiAssistantMongoAggregate(payload, context) {
1107
1258
  return __awaiter(this, void 0, void 0, function () {
1108
- var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, dateField, documents, executedPipeline, fallbackMeta, fallback, fallbackPipeline, fallbackDocs, createdFallback, createdPipeline, createdDocs, unwindFallback, fallbackPipeline, fallbackDocs, sanitizedDocuments, includeIds, display;
1259
+ var input, rawCollection, dbName, db, collectionResolution, collection, _a, user, isSuperAdmin, customerId, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, dateField, aggregateOptions, documents, executedPipeline, fallbackMeta, fallback, fallbackPipeline, fallbackDocs, createdFallback, createdPipeline, createdDocs, completionFallback, fallbackPipeline, fallbackDocs, unwindFallback, fallbackPipeline, fallbackDocs, sanitizedDocuments, includeIds, display;
1109
1260
  var _c, _d;
1110
1261
  return __generator(this, function (_e) {
1111
1262
  switch (_e.label) {
1112
1263
  case 0:
1113
1264
  input = payload || {};
1114
- collection = normalizeOptionalString(input.collection);
1115
- if (!collection) {
1265
+ rawCollection = normalizeOptionalString(input.collection);
1266
+ if (!rawCollection) {
1116
1267
  throw new Error('AI assistant mongo aggregate: Collection is required.');
1117
1268
  }
1118
- return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
1269
+ dbName = resolveAssistantDatabaseName(input.database, input.mongo);
1270
+ db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
1271
+ return [4 /*yield*/, resolveAssistantCollectionName(db, dbName, rawCollection)];
1119
1272
  case 1:
1273
+ collectionResolution = _e.sent();
1274
+ collection = collectionResolution.name || rawCollection;
1275
+ return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
1276
+ case 2:
1120
1277
  _a = _e.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
1121
1278
  if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
1122
1279
  throw new Error('AI assistant mongo aggregate: Access denied.');
1123
1280
  }
1124
1281
  customerId = normalizeOptionalString((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.id_customer);
1125
- dbName = resolveAssistantDatabaseName(input.database, input.mongo);
1126
- db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
1127
1282
  baseQuery = normalizeMongoQuery(input.query);
1128
1283
  if (!isSuperAdmin && (collection === 'users' || collection === 'user-versions')) {
1129
1284
  userId = normalizeOptionalString(user === null || user === void 0 ? void 0 : user._id);
@@ -1135,15 +1290,15 @@ function executeAiAssistantMongoAggregate(payload, context) {
1135
1290
  };
1136
1291
  }
1137
1292
  normalizedClient = normalizeOptionalString(input.id_client);
1138
- if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
1293
+ if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 4];
1139
1294
  return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
1140
- case 2:
1141
- _b = _e.sent();
1142
- return [3 /*break*/, 4];
1143
1295
  case 3:
1144
- _b = false;
1145
- _e.label = 4;
1296
+ _b = _e.sent();
1297
+ return [3 /*break*/, 5];
1146
1298
  case 4:
1299
+ _b = false;
1300
+ _e.label = 5;
1301
+ case 5:
1147
1302
  shouldScopeByClient = _b;
1148
1303
  clientScopedQuery = shouldScopeByClient
1149
1304
  ? applyClientScopeFilter(baseQuery, normalizedClient, isSuperAdmin)
@@ -1157,66 +1312,91 @@ function executeAiAssistantMongoAggregate(payload, context) {
1157
1312
  if (containsForbiddenMongoOperators(limitedPipeline)) {
1158
1313
  throw new Error('AI assistant mongo aggregate: Pipeline contains restricted operators.');
1159
1314
  }
1315
+ aggregateOptions = __assign(__assign({}, normalizedOptions.aggregateOptions), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
1160
1316
  return [4 /*yield*/, db.collection(collection)
1161
- .aggregate(limitedPipeline, normalizedOptions.aggregateOptions)
1317
+ .aggregate(limitedPipeline, aggregateOptions)
1162
1318
  .toArray()];
1163
- case 5:
1319
+ case 6:
1164
1320
  documents = _e.sent();
1165
1321
  executedPipeline = limitedPipeline;
1166
1322
  fallbackMeta = {};
1167
- if (!(!documents.length && dateField)) return [3 /*break*/, 9];
1323
+ if (!(!documents.length && dateField)) return [3 /*break*/, 10];
1168
1324
  fallback = resolveAggregateDateFieldFallback(limitedPipeline);
1169
- if (!fallback) return [3 /*break*/, 7];
1325
+ if (!fallback) return [3 /*break*/, 8];
1170
1326
  fallbackMeta.dateField = __assign(__assign({}, fallback), { attempted: true, used: false });
1171
1327
  fallbackPipeline = replaceAggregateDateField(limitedPipeline, fallback.from, fallback.to);
1172
- if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 7];
1328
+ if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 8];
1173
1329
  return [4 /*yield*/, db.collection(collection)
1174
- .aggregate(fallbackPipeline, normalizedOptions.aggregateOptions)
1330
+ .aggregate(fallbackPipeline, aggregateOptions)
1175
1331
  .toArray()];
1176
- case 6:
1332
+ case 7:
1177
1333
  fallbackDocs = _e.sent();
1178
1334
  if (fallbackDocs.length) {
1179
1335
  documents = fallbackDocs;
1180
1336
  executedPipeline = fallbackPipeline;
1181
1337
  fallbackMeta.dateField.used = true;
1182
1338
  }
1183
- _e.label = 7;
1184
- case 7:
1185
- if (!(!documents.length && dateField !== 'createdAt')) return [3 /*break*/, 9];
1339
+ _e.label = 8;
1340
+ case 8:
1341
+ if (!(!documents.length && dateField !== 'createdAt')) return [3 /*break*/, 10];
1186
1342
  createdFallback = { from: dateField, to: 'createdAt', attempted: true, used: false };
1187
1343
  createdPipeline = replaceAggregateDateField(limitedPipeline, dateField, 'createdAt');
1188
1344
  fallbackMeta.dateFieldCreatedAt = createdFallback;
1189
- if (!!containsForbiddenMongoOperators(createdPipeline)) return [3 /*break*/, 9];
1345
+ if (!!containsForbiddenMongoOperators(createdPipeline)) return [3 /*break*/, 10];
1190
1346
  return [4 /*yield*/, db.collection(collection)
1191
- .aggregate(createdPipeline, normalizedOptions.aggregateOptions)
1347
+ .aggregate(createdPipeline, aggregateOptions)
1192
1348
  .toArray()];
1193
- case 8:
1349
+ case 9:
1194
1350
  createdDocs = _e.sent();
1195
1351
  if (createdDocs.length) {
1196
1352
  documents = createdDocs;
1197
1353
  executedPipeline = createdPipeline;
1198
1354
  fallbackMeta.dateFieldCreatedAt.used = true;
1199
1355
  }
1200
- _e.label = 9;
1201
- case 9:
1202
- if (!(documents.length <= 1)) return [3 /*break*/, 11];
1356
+ _e.label = 10;
1357
+ case 10:
1358
+ if (!!documents.length) return [3 /*break*/, 12];
1359
+ completionFallback = resolveAggregateCompletionFallback(executedPipeline);
1360
+ if (!completionFallback) return [3 /*break*/, 12];
1361
+ fallbackMeta.completion = {
1362
+ field: completionFallback.field,
1363
+ sources: completionFallback.sources,
1364
+ attempted: true,
1365
+ used: false,
1366
+ statusFilter: !!completionFallback.statusFilter
1367
+ };
1368
+ fallbackPipeline = buildAggregateCompletionFallbackPipeline(executedPipeline, completionFallback);
1369
+ if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 12];
1370
+ return [4 /*yield*/, db.collection(collection)
1371
+ .aggregate(fallbackPipeline, aggregateOptions)
1372
+ .toArray()];
1373
+ case 11:
1374
+ fallbackDocs = _e.sent();
1375
+ if (fallbackDocs.length) {
1376
+ documents = fallbackDocs;
1377
+ executedPipeline = fallbackPipeline;
1378
+ fallbackMeta.completion.used = true;
1379
+ }
1380
+ _e.label = 12;
1381
+ case 12:
1382
+ if (!(documents.length <= 1)) return [3 /*break*/, 14];
1203
1383
  unwindFallback = resolveAggregateUnwindFallback(executedPipeline);
1204
- if (!unwindFallback) return [3 /*break*/, 11];
1384
+ if (!unwindFallback) return [3 /*break*/, 14];
1205
1385
  fallbackMeta.unwind = { path: unwindFallback.path, attempted: true, used: false };
1206
1386
  fallbackPipeline = buildAggregateUnwindFallbackPipeline(executedPipeline, unwindFallback);
1207
- if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 11];
1387
+ if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 14];
1208
1388
  return [4 /*yield*/, db.collection(collection)
1209
- .aggregate(fallbackPipeline, normalizedOptions.aggregateOptions)
1389
+ .aggregate(fallbackPipeline, aggregateOptions)
1210
1390
  .toArray()];
1211
- case 10:
1391
+ case 13:
1212
1392
  fallbackDocs = _e.sent();
1213
1393
  if (fallbackDocs.length > documents.length) {
1214
1394
  documents = fallbackDocs;
1215
1395
  executedPipeline = fallbackPipeline;
1216
1396
  fallbackMeta.unwind.used = true;
1217
1397
  }
1218
- _e.label = 11;
1219
- case 11:
1398
+ _e.label = 14;
1399
+ case 14:
1220
1400
  sanitizedDocuments = isSuperAdmin
1221
1401
  ? documents
1222
1402
  : documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
@@ -1229,6 +1409,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
1229
1409
  return [2 /*return*/, __assign({ documents: sanitizedDocuments, display: display }, (isSuperAdmin ? {
1230
1410
  debug: {
1231
1411
  collection: collection,
1412
+ collectionRequested: rawCollection,
1413
+ collectionResolved: collection,
1414
+ collectionMatched: collectionResolution.matched,
1415
+ collectionCandidates: collectionResolution.candidates,
1416
+ collectionScore: collectionResolution.score,
1232
1417
  database: dbName,
1233
1418
  query: scopedQuery,
1234
1419
  options: normalizedOptions.aggregateOptions,
@@ -1299,7 +1484,7 @@ function buildAssistantToolRequest(directive, payload) {
1299
1484
  return request;
1300
1485
  }
1301
1486
  function buildAssistantToolResultPayload(directive, toolResponse) {
1302
- var _a;
1487
+ var _a, _b, _c;
1303
1488
  var directivePayload = directive.payload || {};
1304
1489
  var documents = Array.isArray(toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.documents) ? toolResponse.documents : [];
1305
1490
  var includeIds = ((_a = directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.options) === null || _a === void 0 ? void 0 : _a.includeIds) === true;
@@ -1316,17 +1501,22 @@ function buildAssistantToolResultPayload(directive, toolResponse) {
1316
1501
  });
1317
1502
  var total = typeof (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.total) === 'number' ? toolResponse.total : null;
1318
1503
  var rowCount = documents.length || trimmedDisplay.rowCount;
1319
- var collection = normalizeOptionalString(directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.collection) || '';
1504
+ var requestedCollection = normalizeOptionalString(directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.collection);
1505
+ var resolvedCollection = normalizeOptionalString((_b = toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) === null || _b === void 0 ? void 0 : _b.collectionResolved)
1506
+ || normalizeOptionalString((_c = toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) === null || _c === void 0 ? void 0 : _c.collection)
1507
+ || requestedCollection
1508
+ || '';
1320
1509
  var result = {
1321
1510
  type: directive.type === 'aggregate' ? 'mongo_agg' : 'mongo_read',
1322
1511
  input: directivePayload,
1323
1512
  output: {
1324
1513
  display: trimmedDisplay,
1325
1514
  total: total !== null ? total : undefined,
1326
- collection: collection || undefined,
1515
+ collection: resolvedCollection || undefined,
1327
1516
  rowCount: rowCount,
1328
1517
  columns: trimmedDisplay.columns,
1329
- truncated: trimmedDisplay.truncated
1518
+ truncated: trimmedDisplay.truncated,
1519
+ debug: (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) && typeof toolResponse.debug === 'object' ? toolResponse.debug : undefined
1330
1520
  }
1331
1521
  };
1332
1522
  return {
@@ -1382,6 +1572,82 @@ function buildAssistantToolFallbackResponse(result) {
1382
1572
  }
1383
1573
  return lines.join('\n').trim();
1384
1574
  }
1575
+ function buildAssistantDebugPayload(params) {
1576
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
1577
+ var notes = [];
1578
+ if (params.dataQuestion) {
1579
+ notes.push('Detected a data request; tool call required.');
1580
+ }
1581
+ if (params.directiveSource === 'forced') {
1582
+ notes.push('Assistant response omitted a MONGO_* directive; ran a directive-only pass.');
1583
+ }
1584
+ var directive = params.directive;
1585
+ var directivePayload = (directive === null || directive === void 0 ? void 0 : directive.payload) || {};
1586
+ var rawCollection = normalizeOptionalString(directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.collection);
1587
+ var debugCollectionRequested = normalizeOptionalString((_a = params.toolResponseDebug) === null || _a === void 0 ? void 0 : _a.collectionRequested);
1588
+ var debugCollectionResolved = normalizeOptionalString((_b = params.toolResponseDebug) === null || _b === void 0 ? void 0 : _b.collectionResolved);
1589
+ var debugCollection = normalizeOptionalString((_c = params.toolResponseDebug) === null || _c === void 0 ? void 0 : _c.collection);
1590
+ var requestedCollection = debugCollectionRequested || rawCollection;
1591
+ var resolvedCollection = debugCollectionResolved || debugCollection || requestedCollection;
1592
+ var matchedCollection = typeof ((_d = params.toolResponseDebug) === null || _d === void 0 ? void 0 : _d.collectionMatched) === 'boolean'
1593
+ ? params.toolResponseDebug.collectionMatched
1594
+ : undefined;
1595
+ var candidateCollections = Array.isArray((_e = params.toolResponseDebug) === null || _e === void 0 ? void 0 : _e.collectionCandidates)
1596
+ ? params.toolResponseDebug.collectionCandidates.filter(Boolean)
1597
+ : [];
1598
+ if (requestedCollection && resolvedCollection && requestedCollection !== resolvedCollection) {
1599
+ notes.push("Resolved collection \"".concat(requestedCollection, "\" -> \"").concat(resolvedCollection, "\"."));
1600
+ }
1601
+ else if (matchedCollection === false && candidateCollections.length) {
1602
+ notes.push("No direct collection match; candidates: ".concat(candidateCollections.join(', '), "."));
1603
+ }
1604
+ if (((_f = params.toolResult) === null || _f === void 0 ? void 0 : _f.type) === 'mongo_agg') {
1605
+ notes.push('Used aggregation for grouped/breakdown request.');
1606
+ }
1607
+ else if (((_g = params.toolResult) === null || _g === void 0 ? void 0 : _g.type) === 'mongo_read') {
1608
+ notes.push('Used read query for list/count request.');
1609
+ }
1610
+ var fallbackInfo = (_h = params.toolResponseDebug) === null || _h === void 0 ? void 0 : _h.fallbacks;
1611
+ if ((_j = fallbackInfo === null || fallbackInfo === void 0 ? void 0 : fallbackInfo.dateField) === null || _j === void 0 ? void 0 : _j.used) {
1612
+ notes.push("Retried with date field fallback ".concat(fallbackInfo.dateField.from, " -> ").concat(fallbackInfo.dateField.to, "."));
1613
+ }
1614
+ if ((_k = fallbackInfo === null || fallbackInfo === void 0 ? void 0 : fallbackInfo.dateFieldCreatedAt) === null || _k === void 0 ? void 0 : _k.used) {
1615
+ notes.push("Retried with date field fallback ".concat(fallbackInfo.dateFieldCreatedAt.from, " -> ").concat(fallbackInfo.dateFieldCreatedAt.to, "."));
1616
+ }
1617
+ if ((_l = fallbackInfo === null || fallbackInfo === void 0 ? void 0 : fallbackInfo.unwind) === null || _l === void 0 ? void 0 : _l.used) {
1618
+ notes.push("Applied unwind fallback on ".concat(fallbackInfo.unwind.path, "."));
1619
+ }
1620
+ if (params.toolError) {
1621
+ var errorMessage = ((_m = params.toolError) === null || _m === void 0 ? void 0 : _m.message) || String(params.toolError || '');
1622
+ if (errorMessage) {
1623
+ notes.push("Tool error: ".concat(errorMessage));
1624
+ }
1625
+ }
1626
+ return {
1627
+ decision: {
1628
+ dataQuestion: params.dataQuestion,
1629
+ directiveSource: params.directiveSource
1630
+ },
1631
+ directive: directive ? {
1632
+ type: directive.type,
1633
+ payload: directivePayload,
1634
+ rawLine: directive.rawLine
1635
+ } : null,
1636
+ collection: resolvedCollection || requestedCollection || undefined,
1637
+ collectionRequested: requestedCollection || undefined,
1638
+ collectionResolved: resolvedCollection || undefined,
1639
+ collectionMatched: matchedCollection,
1640
+ collectionCandidates: candidateCollections.length ? candidateCollections : undefined,
1641
+ collectionScore: typeof ((_o = params.toolResponseDebug) === null || _o === void 0 ? void 0 : _o.collectionScore) === 'number'
1642
+ ? params.toolResponseDebug.collectionScore
1643
+ : undefined,
1644
+ query: ((_p = params.toolResponseDebug) === null || _p === void 0 ? void 0 : _p.query) || undefined,
1645
+ pipeline: ((_q = params.toolResponseDebug) === null || _q === void 0 ? void 0 : _q.executedPipeline) || ((_r = params.toolResponseDebug) === null || _r === void 0 ? void 0 : _r.originalPipeline) || undefined,
1646
+ options: ((_s = params.toolResponseDebug) === null || _s === void 0 ? void 0 : _s.options) || undefined,
1647
+ fallbacks: ((_t = params.toolResponseDebug) === null || _t === void 0 ? void 0 : _t.fallbacks) || undefined,
1648
+ notes: notes
1649
+ };
1650
+ }
1385
1651
  function buildAssistantToolErrorMessage(error, directive, request) {
1386
1652
  var _a, _b;
1387
1653
  var rawMessage = normalizeOptionalString(error === null || error === void 0 ? void 0 : error.message) || 'Unable to access data.';
@@ -2006,7 +2272,18 @@ function normalizeAssistantAggregatePipeline(pipeline) {
2006
2272
  if (!Array.isArray(pipeline)) {
2007
2273
  return [];
2008
2274
  }
2009
- return pipeline.filter(function (stage) { return stage && typeof stage === 'object' && !Array.isArray(stage); });
2275
+ return pipeline
2276
+ .filter(function (stage) { return stage && typeof stage === 'object' && !Array.isArray(stage); })
2277
+ .map(function (stage) {
2278
+ var next = __assign({}, stage);
2279
+ if (next.$match && typeof next.$match === 'object') {
2280
+ next.$match = applyAssistantNameRegexToQuery(next.$match);
2281
+ }
2282
+ if (next.$geoNear && typeof next.$geoNear === 'object' && next.$geoNear.query) {
2283
+ next.$geoNear = __assign(__assign({}, next.$geoNear), { query: applyAssistantNameRegexToQuery(next.$geoNear.query) });
2284
+ }
2285
+ return next;
2286
+ });
2010
2287
  }
2011
2288
  function buildAssistantAggregatePipeline(query, pipeline) {
2012
2289
  var _a;
@@ -2089,6 +2366,172 @@ function resolveAggregateDateFieldFallback(pipeline) {
2089
2366
  }
2090
2367
  return { from: dateField, to: fallback };
2091
2368
  }
2369
+ function normalizeAggregateFieldList(values) {
2370
+ var seen = new Set();
2371
+ var result = [];
2372
+ values.forEach(function (value) {
2373
+ var normalized = normalizeOptionalString(value);
2374
+ if (!normalized) {
2375
+ return;
2376
+ }
2377
+ if (seen.has(normalized)) {
2378
+ return;
2379
+ }
2380
+ seen.add(normalized);
2381
+ result.push(normalized);
2382
+ });
2383
+ return result;
2384
+ }
2385
+ function isCompletionFieldName(value) {
2386
+ return String(value || '').toLowerCase().includes('complete');
2387
+ }
2388
+ function isDateLikeFieldName(value) {
2389
+ var normalized = String(value || '').toLowerCase();
2390
+ return normalized.includes('date') || normalized.endsWith('_at') || normalized.endsWith('at');
2391
+ }
2392
+ function matchContainsField(value, field) {
2393
+ if (!value || typeof value !== 'object') {
2394
+ return false;
2395
+ }
2396
+ if (Array.isArray(value)) {
2397
+ return value.some(function (entry) { return matchContainsField(entry, field); });
2398
+ }
2399
+ return Object.keys(value).some(function (key) {
2400
+ if (key === field) {
2401
+ return true;
2402
+ }
2403
+ if (key.startsWith('$')) {
2404
+ return matchContainsField(value[key], field);
2405
+ }
2406
+ if (value[key] && typeof value[key] === 'object') {
2407
+ return matchContainsField(value[key], field);
2408
+ }
2409
+ return false;
2410
+ });
2411
+ }
2412
+ function resolveAggregateCompletionFallback(pipeline) {
2413
+ var e_1, _a;
2414
+ if (!Array.isArray(pipeline)) {
2415
+ return null;
2416
+ }
2417
+ var candidateField = '';
2418
+ var candidateSources = [];
2419
+ for (var i = 0; i < pipeline.length; i += 1) {
2420
+ var stage = pipeline[i];
2421
+ if (!stage || typeof stage !== 'object' || !stage.$addFields || typeof stage.$addFields !== 'object') {
2422
+ continue;
2423
+ }
2424
+ var addFields = stage.$addFields;
2425
+ try {
2426
+ for (var _b = (e_1 = void 0, __values(Object.keys(addFields))), _c = _b.next(); !_c.done; _c = _b.next()) {
2427
+ var key = _c.value;
2428
+ if (!isCompletionFieldName(key)) {
2429
+ continue;
2430
+ }
2431
+ var sources = extractExpressionFieldPaths(addFields[key])
2432
+ .filter(function (field) { return isDateLikeFieldName(field); });
2433
+ if (sources.length) {
2434
+ candidateField = key;
2435
+ candidateSources = sources;
2436
+ break;
2437
+ }
2438
+ }
2439
+ }
2440
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2441
+ finally {
2442
+ try {
2443
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2444
+ }
2445
+ finally { if (e_1) throw e_1.error; }
2446
+ }
2447
+ if (candidateField) {
2448
+ break;
2449
+ }
2450
+ }
2451
+ if (!candidateField || !candidateSources.length) {
2452
+ return null;
2453
+ }
2454
+ var matchIndex = -1;
2455
+ var matchCondition = null;
2456
+ var matchStage = null;
2457
+ for (var i = 0; i < pipeline.length; i += 1) {
2458
+ var stage = pipeline[i];
2459
+ if (!stage || typeof stage !== 'object' || !stage.$match || typeof stage.$match !== 'object') {
2460
+ continue;
2461
+ }
2462
+ if (Object.prototype.hasOwnProperty.call(stage.$match, candidateField)) {
2463
+ matchIndex = i;
2464
+ matchCondition = stage.$match[candidateField];
2465
+ matchStage = stage.$match;
2466
+ break;
2467
+ }
2468
+ }
2469
+ if (matchIndex === -1 || !matchStage) {
2470
+ return null;
2471
+ }
2472
+ var normalizedSources = normalizeAggregateFieldList(__spreadArray(__spreadArray([], __read(candidateSources), false), [
2473
+ 'createdAt',
2474
+ 'date_created'
2475
+ ], false));
2476
+ if (!normalizedSources.length) {
2477
+ return null;
2478
+ }
2479
+ var hasStatus = matchContainsField(matchStage, 'status') || matchContainsField(matchStage, 'state');
2480
+ var statusFilter = !hasStatus && isCompletionFieldName(candidateField)
2481
+ ? { $or: [{ status: { $regex: 'complete', $options: 'i' } }, { state: { $regex: 'complete', $options: 'i' } }] }
2482
+ : null;
2483
+ return {
2484
+ matchIndex: matchIndex,
2485
+ field: candidateField,
2486
+ sources: normalizedSources,
2487
+ matchCondition: matchCondition,
2488
+ statusFilter: statusFilter
2489
+ };
2490
+ }
2491
+ function buildAggregateCompletionFallbackPipeline(pipeline, fallback) {
2492
+ var _a;
2493
+ var buildIfNullChain = function (fields) {
2494
+ if (!fields.length) {
2495
+ return null;
2496
+ }
2497
+ var expr = "$".concat(fields[fields.length - 1]);
2498
+ for (var i = fields.length - 2; i >= 0; i -= 1) {
2499
+ expr = { $ifNull: ["$".concat(fields[i]), expr] };
2500
+ }
2501
+ return expr;
2502
+ };
2503
+ var matchStage = (_a = pipeline[fallback.matchIndex]) === null || _a === void 0 ? void 0 : _a.$match;
2504
+ if (!matchStage || typeof matchStage !== 'object') {
2505
+ return pipeline;
2506
+ }
2507
+ var orConditions = fallback.sources.map(function (field) {
2508
+ var _a;
2509
+ return (_a = {}, _a[field] = fallback.matchCondition, _a);
2510
+ });
2511
+ var nextMatch = __assign({}, matchStage);
2512
+ delete nextMatch[fallback.field];
2513
+ var andParts = [];
2514
+ if (Object.keys(nextMatch).length) {
2515
+ andParts.push(nextMatch);
2516
+ }
2517
+ andParts.push({ $or: orConditions });
2518
+ if (fallback.statusFilter) {
2519
+ andParts.push(fallback.statusFilter);
2520
+ }
2521
+ var mergedMatch = andParts.length === 1 ? andParts[0] : { $and: andParts };
2522
+ return pipeline.map(function (stage, index) {
2523
+ var _a;
2524
+ if (index === fallback.matchIndex) {
2525
+ return { $match: mergedMatch };
2526
+ }
2527
+ if (stage && typeof stage === 'object' && stage.$addFields && typeof stage.$addFields === 'object') {
2528
+ if (Object.prototype.hasOwnProperty.call(stage.$addFields, fallback.field)) {
2529
+ return __assign(__assign({}, stage), { $addFields: __assign(__assign({}, stage.$addFields), (_a = {}, _a[fallback.field] = buildIfNullChain(fallback.sources), _a)) });
2530
+ }
2531
+ }
2532
+ return stage;
2533
+ });
2534
+ }
2092
2535
  function resolveAggregateUnwindFallback(pipeline) {
2093
2536
  var groupIndex = findAggregateGroupIndex(pipeline);
2094
2537
  if (groupIndex === -1) {
@@ -2275,10 +2718,302 @@ function normalizeMongoQuery(query) {
2275
2718
  if (containsForbiddenMongoOperators(normalized)) {
2276
2719
  throw new Error('AI assistant mongo read: Query contains restricted operators.');
2277
2720
  }
2278
- return normalized;
2721
+ return applyAssistantNameRegexToQuery(normalized);
2722
+ }
2723
+ function shouldApplyAssistantNameRegex(field) {
2724
+ var normalized = String(field || '').toLowerCase().trim();
2725
+ if (!normalized) {
2726
+ return false;
2727
+ }
2728
+ if (normalized.startsWith('$')) {
2729
+ return false;
2730
+ }
2731
+ if (isAssistantIdField(normalized)) {
2732
+ return false;
2733
+ }
2734
+ if (normalized === 'id' || normalized.endsWith('_id')) {
2735
+ return false;
2736
+ }
2737
+ var tokens = normalized.split(/[^a-z0-9]+/g).filter(Boolean);
2738
+ var targetTokens = new Set(['customer', 'well', 'chemical']);
2739
+ var hasTargetToken = tokens.some(function (token) { return targetTokens.has(token); });
2740
+ if (hasTargetToken) {
2741
+ return true;
2742
+ }
2743
+ if (tokens.includes('name')) {
2744
+ return true;
2745
+ }
2746
+ return /(^|[._-])name$/i.test(normalized);
2747
+ }
2748
+ function escapeRegexValue(value) {
2749
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2750
+ }
2751
+ function applyAssistantNameRegexToQuery(query) {
2752
+ if (Array.isArray(query)) {
2753
+ return query.map(function (entry) { return applyAssistantNameRegexToQuery(entry); });
2754
+ }
2755
+ if (!query || typeof query !== 'object' || query instanceof Date || query instanceof RegExp || isMongoObjectId(query)) {
2756
+ return query;
2757
+ }
2758
+ var result = {};
2759
+ Object.keys(query).forEach(function (key) {
2760
+ var value = query[key];
2761
+ if (key.startsWith('$')) {
2762
+ result[key] = applyAssistantNameRegexToQuery(value);
2763
+ return;
2764
+ }
2765
+ if (typeof value === 'string' && shouldApplyAssistantNameRegex(key)) {
2766
+ var trimmed = value.trim();
2767
+ result[key] = trimmed ? new RegExp(escapeRegexValue(trimmed), 'i') : value;
2768
+ return;
2769
+ }
2770
+ if (value && typeof value === 'object') {
2771
+ result[key] = applyAssistantNameRegexToQuery(value);
2772
+ return;
2773
+ }
2774
+ result[key] = value;
2775
+ });
2776
+ return result;
2777
+ }
2778
+ function normalizeCollectionKey(value) {
2779
+ return String(value || '').toLowerCase().replace(/[^a-z0-9]/g, '');
2780
+ }
2781
+ function normalizeCollectionToken(token) {
2782
+ var trimmed = token.trim();
2783
+ if (!trimmed) {
2784
+ return [];
2785
+ }
2786
+ var tokens = new Set([trimmed]);
2787
+ if (trimmed.length > 4
2788
+ && trimmed.endsWith('s')
2789
+ && !trimmed.endsWith('ss')
2790
+ && !trimmed.endsWith('us')
2791
+ && !trimmed.endsWith('is')) {
2792
+ tokens.add(trimmed.slice(0, -1));
2793
+ }
2794
+ return Array.from(tokens);
2795
+ }
2796
+ function tokenizeCollectionText(value) {
2797
+ var rawTokens = String(value || '')
2798
+ .toLowerCase()
2799
+ .split(/[^a-z0-9]+/g)
2800
+ .map(function (token) { return token.trim(); })
2801
+ .filter(Boolean);
2802
+ var tokens = [];
2803
+ rawTokens.forEach(function (token) {
2804
+ normalizeCollectionToken(token).forEach(function (normalized) {
2805
+ if (!AI_ASSISTANT_COLLECTION_STOPWORDS.has(normalized)) {
2806
+ tokens.push(normalized);
2807
+ }
2808
+ });
2809
+ });
2810
+ return Array.from(new Set(tokens));
2811
+ }
2812
+ function listAssistantCollections(db, dbName) {
2813
+ return __awaiter(this, void 0, void 0, function () {
2814
+ var cacheKey, cached, now, collections, names, _a;
2815
+ return __generator(this, function (_b) {
2816
+ switch (_b.label) {
2817
+ case 0:
2818
+ cacheKey = normalizeOptionalString(dbName) || 'default';
2819
+ cached = AI_ASSISTANT_COLLECTION_CACHE.get(cacheKey);
2820
+ now = Date.now();
2821
+ if (cached && now - cached.updatedAt < AI_ASSISTANT_COLLECTION_CACHE_TTL_MS) {
2822
+ return [2 /*return*/, cached.names];
2823
+ }
2824
+ _b.label = 1;
2825
+ case 1:
2826
+ _b.trys.push([1, 3, , 4]);
2827
+ return [4 /*yield*/, db.listCollections({}, { nameOnly: true }).toArray()];
2828
+ case 2:
2829
+ collections = _b.sent();
2830
+ names = Array.isArray(collections)
2831
+ ? collections.map(function (entry) { return normalizeOptionalString(entry === null || entry === void 0 ? void 0 : entry.name); }).filter(Boolean)
2832
+ : [];
2833
+ AI_ASSISTANT_COLLECTION_CACHE.set(cacheKey, { names: names, updatedAt: now });
2834
+ return [2 /*return*/, names];
2835
+ case 3:
2836
+ _a = _b.sent();
2837
+ return [2 /*return*/, (cached === null || cached === void 0 ? void 0 : cached.names) || []];
2838
+ case 4: return [2 /*return*/];
2839
+ }
2840
+ });
2841
+ });
2842
+ }
2843
+ function scoreCollectionMatch(requestedTokens, candidateName) {
2844
+ if (!requestedTokens.length) {
2845
+ return 0;
2846
+ }
2847
+ var candidateTokens = tokenizeCollectionText(candidateName);
2848
+ if (!candidateTokens.length) {
2849
+ return 0;
2850
+ }
2851
+ var score = 0;
2852
+ requestedTokens.forEach(function (token) {
2853
+ if (candidateTokens.includes(token)) {
2854
+ score += 10;
2855
+ }
2856
+ });
2857
+ var requestedKey = normalizeCollectionKey(requestedTokens.join('-'));
2858
+ var candidateKey = normalizeCollectionKey(candidateName);
2859
+ if (candidateKey === requestedKey && requestedKey) {
2860
+ score += 50;
2861
+ }
2862
+ else if (requestedKey && (candidateKey.includes(requestedKey) || requestedKey.includes(candidateKey))) {
2863
+ score += 20;
2864
+ }
2865
+ return score;
2866
+ }
2867
+ function findBestCollectionMatch(requested, collectionNames) {
2868
+ var requestedTokens = tokenizeCollectionText(requested);
2869
+ if (!requestedTokens.length || !collectionNames.length) {
2870
+ return null;
2871
+ }
2872
+ var best = null;
2873
+ collectionNames.forEach(function (name) {
2874
+ var score = scoreCollectionMatch(requestedTokens, name);
2875
+ if (!best || score > best.score) {
2876
+ best = { name: name, score: score };
2877
+ }
2878
+ });
2879
+ return best;
2880
+ }
2881
+ function resolveAssistantCollectionName(db, dbName, requested) {
2882
+ return __awaiter(this, void 0, void 0, function () {
2883
+ var trimmed, collectionNames, best, candidates;
2884
+ return __generator(this, function (_a) {
2885
+ switch (_a.label) {
2886
+ case 0:
2887
+ trimmed = normalizeOptionalString(requested);
2888
+ if (!trimmed) {
2889
+ return [2 /*return*/, { name: '', matched: false, candidates: [], score: 0 }];
2890
+ }
2891
+ return [4 /*yield*/, listAssistantCollections(db, dbName)];
2892
+ case 1:
2893
+ collectionNames = _a.sent();
2894
+ if (collectionNames.includes(trimmed)) {
2895
+ return [2 /*return*/, { name: trimmed, matched: true, candidates: [], score: 100 }];
2896
+ }
2897
+ best = findBestCollectionMatch(trimmed, collectionNames);
2898
+ if (best && best.score >= 20) {
2899
+ return [2 /*return*/, { name: best.name, matched: true, candidates: [], score: best.score }];
2900
+ }
2901
+ candidates = collectionNames
2902
+ .map(function (name) { return ({ name: name, score: scoreCollectionMatch(tokenizeCollectionText(trimmed), name) }); })
2903
+ .filter(function (entry) { return entry.score > 0; })
2904
+ .sort(function (a, b) { return b.score - a.score; })
2905
+ .slice(0, 5)
2906
+ .map(function (entry) { return entry.name; });
2907
+ return [2 /*return*/, { name: trimmed, matched: false, candidates: candidates, score: (best === null || best === void 0 ? void 0 : best.score) || 0 }];
2908
+ }
2909
+ });
2910
+ });
2911
+ }
2912
+ function resolveAssistantCollectionHints(message, dbName, db) {
2913
+ return __awaiter(this, void 0, void 0, function () {
2914
+ var text, collectionNames, tokens;
2915
+ return __generator(this, function (_a) {
2916
+ switch (_a.label) {
2917
+ case 0:
2918
+ text = normalizeOptionalString(message);
2919
+ if (!text) {
2920
+ return [2 /*return*/, []];
2921
+ }
2922
+ return [4 /*yield*/, listAssistantCollections(db, dbName)];
2923
+ case 1:
2924
+ collectionNames = _a.sent();
2925
+ if (!collectionNames.length) {
2926
+ return [2 /*return*/, []];
2927
+ }
2928
+ tokens = tokenizeCollectionText(text);
2929
+ if (!tokens.length) {
2930
+ return [2 /*return*/, []];
2931
+ }
2932
+ return [2 /*return*/, collectionNames
2933
+ .map(function (name) { return ({ name: name, score: scoreCollectionMatch(tokens, name) }); })
2934
+ .filter(function (entry) { return entry.score > 0; })
2935
+ .sort(function (a, b) { return b.score - a.score; })
2936
+ .slice(0, 5)
2937
+ .map(function (entry) { return entry.name; })];
2938
+ }
2939
+ });
2940
+ });
2941
+ }
2942
+ function findQueryDateField(query) {
2943
+ var e_2, _a, e_3, _b;
2944
+ if (!query || typeof query !== 'object') {
2945
+ return null;
2946
+ }
2947
+ if (Array.isArray(query)) {
2948
+ try {
2949
+ for (var query_1 = __values(query), query_1_1 = query_1.next(); !query_1_1.done; query_1_1 = query_1.next()) {
2950
+ var entry = query_1_1.value;
2951
+ var found = findQueryDateField(entry);
2952
+ if (found) {
2953
+ return found;
2954
+ }
2955
+ }
2956
+ }
2957
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
2958
+ finally {
2959
+ try {
2960
+ if (query_1_1 && !query_1_1.done && (_a = query_1.return)) _a.call(query_1);
2961
+ }
2962
+ finally { if (e_2) throw e_2.error; }
2963
+ }
2964
+ return null;
2965
+ }
2966
+ try {
2967
+ for (var _c = __values(Object.keys(query)), _d = _c.next(); !_d.done; _d = _c.next()) {
2968
+ var key = _d.value;
2969
+ if (key.startsWith('$')) {
2970
+ var found = findQueryDateField(query[key]);
2971
+ if (found) {
2972
+ return found;
2973
+ }
2974
+ continue;
2975
+ }
2976
+ if (AI_ASSISTANT_DATE_FALLBACKS[key]) {
2977
+ return key;
2978
+ }
2979
+ }
2980
+ }
2981
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
2982
+ finally {
2983
+ try {
2984
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
2985
+ }
2986
+ finally { if (e_3) throw e_3.error; }
2987
+ }
2988
+ return null;
2989
+ }
2990
+ function replaceQueryField(query, fromField, toField) {
2991
+ if (Array.isArray(query)) {
2992
+ return query.map(function (entry) { return replaceQueryField(entry, fromField, toField); });
2993
+ }
2994
+ if (!query || typeof query !== 'object' || query instanceof Date) {
2995
+ return query;
2996
+ }
2997
+ var result = {};
2998
+ Object.keys(query).forEach(function (key) {
2999
+ var nextKey = key === fromField ? toField : key;
3000
+ result[nextKey] = replaceQueryField(query[key], fromField, toField);
3001
+ });
3002
+ return result;
3003
+ }
3004
+ function resolveQueryDateFieldFallback(query) {
3005
+ var dateField = findQueryDateField(query);
3006
+ if (!dateField) {
3007
+ return null;
3008
+ }
3009
+ var fallback = AI_ASSISTANT_DATE_FALLBACKS[dateField];
3010
+ if (!fallback) {
3011
+ return null;
3012
+ }
3013
+ return { from: dateField, to: fallback };
2279
3014
  }
2280
3015
  function containsForbiddenMongoOperators(value) {
2281
- var e_1, _a;
3016
+ var e_4, _a;
2282
3017
  if (!value || typeof value !== 'object') {
2283
3018
  return false;
2284
3019
  }
@@ -2297,12 +3032,12 @@ function containsForbiddenMongoOperators(value) {
2297
3032
  }
2298
3033
  }
2299
3034
  }
2300
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3035
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
2301
3036
  finally {
2302
3037
  try {
2303
3038
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2304
3039
  }
2305
- finally { if (e_1) throw e_1.error; }
3040
+ finally { if (e_4) throw e_4.error; }
2306
3041
  }
2307
3042
  return false;
2308
3043
  }
@@ -2465,6 +3200,20 @@ function resolveCodexModel() {
2465
3200
  || process.env.AI_DASHBOARD_CODEX_MODEL);
2466
3201
  return raw || DEFAULT_CODEX_MODEL;
2467
3202
  }
3203
+ function resolveCodexThoughtLevel() {
3204
+ var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
3205
+ var raw = normalizeOptionalString(config['AI_ASSISTANT_CODEX_THOUGHT_LEVEL']
3206
+ || process.env.AI_ASSISTANT_CODEX_THOUGHT_LEVEL
3207
+ || config['AI_TERMINAL_CODEX_THOUGHT_LEVEL']
3208
+ || process.env.AI_TERMINAL_CODEX_THOUGHT_LEVEL
3209
+ || config['AI_DASHBOARD_CODEX_THOUGHT_LEVEL']
3210
+ || process.env.AI_DASHBOARD_CODEX_THOUGHT_LEVEL);
3211
+ var normalized = (raw || '').trim().toLowerCase();
3212
+ if (normalized === 'minimal' || normalized === 'low' || normalized === 'medium' || normalized === 'high' || normalized === 'xhigh') {
3213
+ return normalized;
3214
+ }
3215
+ return 'low';
3216
+ }
2468
3217
  function resolveCodexSettings() {
2469
3218
  var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
2470
3219
  var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
@@ -2522,8 +3271,8 @@ function applyCodexStreamStatusHandler(runOptions, streamStatusHandler) {
2522
3271
  }
2523
3272
  function waitForCodexWorkerMessage(worker, streamStatusHandler) {
2524
3273
  return __awaiter(this, void 0, void 0, function () {
2525
- var _a, _b, _c, _d, message, payload, status_1, e_2_1;
2526
- var _e, e_2, _f, _g;
3274
+ var _a, _b, _c, _d, message, payload, status_1, e_5_1;
3275
+ var _e, e_5, _f, _g;
2527
3276
  return __generator(this, function (_h) {
2528
3277
  switch (_h.label) {
2529
3278
  case 0:
@@ -2550,8 +3299,8 @@ function waitForCodexWorkerMessage(worker, streamStatusHandler) {
2550
3299
  return [3 /*break*/, 1];
2551
3300
  case 4: return [3 /*break*/, 11];
2552
3301
  case 5:
2553
- e_2_1 = _h.sent();
2554
- e_2 = { error: e_2_1 };
3302
+ e_5_1 = _h.sent();
3303
+ e_5 = { error: e_5_1 };
2555
3304
  return [3 /*break*/, 11];
2556
3305
  case 6:
2557
3306
  _h.trys.push([6, , 9, 10]);
@@ -2562,7 +3311,7 @@ function waitForCodexWorkerMessage(worker, streamStatusHandler) {
2562
3311
  _h.label = 8;
2563
3312
  case 8: return [3 /*break*/, 10];
2564
3313
  case 9:
2565
- if (e_2) throw e_2.error;
3314
+ if (e_5) throw e_5.error;
2566
3315
  return [7 /*endfinally*/];
2567
3316
  case 10: return [7 /*endfinally*/];
2568
3317
  case 11: throw new CodexWorkerBootstrapError('Codex worker exited before completing.');
@@ -2838,6 +3587,43 @@ function resolveAssistantWorkspaceRoot() {
2838
3587
  });
2839
3588
  });
2840
3589
  }
3590
+ function isAssistantDataQuestion(message) {
3591
+ var text = normalizeOptionalString(message).toLowerCase();
3592
+ if (!text) {
3593
+ return false;
3594
+ }
3595
+ var patterns = [
3596
+ /\bshow\b/,
3597
+ /\blist\b/,
3598
+ /\bhow many\b/,
3599
+ /\bcount\b/,
3600
+ /\btotal\b/,
3601
+ /\bnumber of\b/,
3602
+ /\blast\b/,
3603
+ /\brecent\b/,
3604
+ /\bthis week\b/,
3605
+ /\blast month\b/,
3606
+ /\boverdue\b/,
3607
+ /\bopen\b/,
3608
+ /\bclosed\b/,
3609
+ /\bcompleted\b/,
3610
+ /\bmissing\b/,
3611
+ /\bgroup(ed)? by\b/,
3612
+ /\bbreakdown\b/,
3613
+ /\bper day\b/,
3614
+ /\bper week\b/,
3615
+ /\bper month\b/
3616
+ ];
3617
+ return patterns.some(function (pattern) { return pattern.test(text); });
3618
+ }
3619
+ function buildAssistantCodexDirectivePrompt(message, attachmentText, historyText, contextText) {
3620
+ var trimmedContext = normalizeOptionalString(contextText);
3621
+ var contextBlock = trimmedContext ? "\n\nContext:\n".concat(trimmedContext) : '';
3622
+ var trimmedHistory = normalizeOptionalString(historyText);
3623
+ var historyBlock = trimmedHistory ? "\n\nConversation so far:\n".concat(trimmedHistory) : '';
3624
+ var instruction = '\n\nInstruction:\nReturn ONLY a single MONGO_READ or MONGO_AGG directive line. Do not include any other text.';
3625
+ return "System:\n".concat(AI_ASSISTANT_SYSTEM_PROMPT).concat(contextBlock).concat(historyBlock, "\n\nUser:\n").concat(message).concat(attachmentText || '').concat(instruction).trim();
3626
+ }
2841
3627
  function buildAssistantCodexPrompt(message, attachmentText, historyText, contextText) {
2842
3628
  var trimmedContext = normalizeOptionalString(contextText);
2843
3629
  var contextBlock = trimmedContext ? "\n\nContext:\n".concat(trimmedContext) : '';
@@ -2871,6 +3657,12 @@ function buildAssistantContext(input, userContext) {
2871
3657
  if (contextRoute) {
2872
3658
  lines.push("Current page route: ".concat(contextRoute));
2873
3659
  }
3660
+ var collectionHints = Array.isArray(userContext === null || userContext === void 0 ? void 0 : userContext.collectionHints)
3661
+ ? userContext === null || userContext === void 0 ? void 0 : userContext.collectionHints.filter(Boolean)
3662
+ : [];
3663
+ if (collectionHints.length) {
3664
+ lines.push("Collection hints: ".concat(collectionHints.join(', ')));
3665
+ }
2874
3666
  var mongoDb = normalizeOptionalString((_c = input === null || input === void 0 ? void 0 : input.mongo) === null || _c === void 0 ? void 0 : _c.database);
2875
3667
  var mongoDbs = Array.isArray((_d = input === null || input === void 0 ? void 0 : input.mongo) === null || _d === void 0 ? void 0 : _d.databases)
2876
3668
  ? input.mongo.databases.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
@@ -2901,7 +3693,7 @@ function normalizeRouteMatchKey(value) {
2901
3693
  return normalizeRouteKey(value).toLowerCase();
2902
3694
  }
2903
3695
  function buildClientRouteIndex() {
2904
- var e_3, _a;
3696
+ var e_6, _a;
2905
3697
  var _b;
2906
3698
  var routes = ((_b = resolveio_server_app_1.ResolveIOServer.getClientRoutes) === null || _b === void 0 ? void 0 : _b.call(resolveio_server_app_1.ResolveIOServer)) || [];
2907
3699
  var set = new Set();
@@ -2920,12 +3712,12 @@ function buildClientRouteIndex() {
2920
3712
  }
2921
3713
  }
2922
3714
  }
2923
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
3715
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
2924
3716
  finally {
2925
3717
  try {
2926
3718
  if (routes_1_1 && !routes_1_1.done && (_a = routes_1.return)) _a.call(routes_1);
2927
3719
  }
2928
- finally { if (e_3) throw e_3.error; }
3720
+ finally { if (e_6) throw e_6.error; }
2929
3721
  }
2930
3722
  return { set: set, map: map, size: routes.length };
2931
3723
  }
@@ -3045,10 +3837,13 @@ function sanitizeAssistantResponse(value) {
3045
3837
  if (!cleaned) {
3046
3838
  return 'I can’t share code, but I can point you to files or explain behavior at a high level.';
3047
3839
  }
3048
- return normalizeAssistantRoutes(cleaned);
3840
+ var normalizedCurrency = cleaned.replace(/\bUSD\s*([0-9][0-9,]*(?:\.[0-9]+)?)/g, function (_match, amount) {
3841
+ return "$".concat(amount);
3842
+ });
3843
+ return normalizeAssistantRoutes(normalizedCurrency);
3049
3844
  }
3050
3845
  function evaluateAssistantGuardrails(message) {
3051
- var e_4, _a;
3846
+ var e_7, _a;
3052
3847
  var normalized = String(message || '').toLowerCase();
3053
3848
  var patterns = [
3054
3849
  {
@@ -3094,12 +3889,12 @@ function evaluateAssistantGuardrails(message) {
3094
3889
  }
3095
3890
  }
3096
3891
  }
3097
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
3892
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
3098
3893
  finally {
3099
3894
  try {
3100
3895
  if (patterns_1_1 && !patterns_1_1.done && (_a = patterns_1.return)) _a.call(patterns_1);
3101
3896
  }
3102
- finally { if (e_4) throw e_4.error; }
3897
+ finally { if (e_7) throw e_7.error; }
3103
3898
  }
3104
3899
  return null;
3105
3900
  }
@@ -3263,8 +4058,8 @@ function handleCodexUpload(id_conversation, file_name, content_base64, size, con
3263
4058
  }
3264
4059
  function readAttachmentContents(attachments) {
3265
4060
  return __awaiter(this, void 0, void 0, function () {
3266
- var limits, totalBytes, totalChars, chunks, cleaned, attachments_1, attachments_1_1, attachment, localPath, safe, stat, ext, name_1, type, readable, content, _a, e_5_1;
3267
- var e_5, _b;
4061
+ var limits, totalBytes, totalChars, chunks, cleaned, attachments_1, attachments_1_1, attachment, localPath, safe, stat, ext, name_1, type, readable, content, _a, e_8_1;
4062
+ var e_8, _b;
3268
4063
  return __generator(this, function (_c) {
3269
4064
  switch (_c.label) {
3270
4065
  case 0:
@@ -3343,14 +4138,14 @@ function readAttachmentContents(attachments) {
3343
4138
  return [3 /*break*/, 2];
3344
4139
  case 10: return [3 /*break*/, 13];
3345
4140
  case 11:
3346
- e_5_1 = _c.sent();
3347
- e_5 = { error: e_5_1 };
4141
+ e_8_1 = _c.sent();
4142
+ e_8 = { error: e_8_1 };
3348
4143
  return [3 /*break*/, 13];
3349
4144
  case 12:
3350
4145
  try {
3351
4146
  if (attachments_1_1 && !attachments_1_1.done && (_b = attachments_1.return)) _b.call(attachments_1);
3352
4147
  }
3353
- finally { if (e_5) throw e_5.error; }
4148
+ finally { if (e_8) throw e_8.error; }
3354
4149
  return [7 /*endfinally*/];
3355
4150
  case 13: return [2 /*return*/, {
3356
4151
  promptText: chunks.length ? "\n\nAttachments:\n".concat(chunks.join('\n\n')) : '',
@@ -3527,7 +4322,7 @@ function estimateUsage(messages, responseText, model) {
3527
4322
  };
3528
4323
  }
3529
4324
  function evaluateGuardrails(message) {
3530
- var e_6, _a;
4325
+ var e_9, _a;
3531
4326
  var normalized = String(message || '').toLowerCase();
3532
4327
  var patterns = [
3533
4328
  { pattern: /\b(source\s*code|full\s*code|entire\s*code|repo\s*dump|repository|git\s*clone)\b/i, reason: 'Code access is restricted.' },
@@ -3549,12 +4344,12 @@ function evaluateGuardrails(message) {
3549
4344
  }
3550
4345
  }
3551
4346
  }
3552
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
4347
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
3553
4348
  finally {
3554
4349
  try {
3555
4350
  if (patterns_2_1 && !patterns_2_1.done && (_a = patterns_2.return)) _a.call(patterns_2);
3556
4351
  }
3557
- finally { if (e_6) throw e_6.error; }
4352
+ finally { if (e_9) throw e_9.error; }
3558
4353
  }
3559
4354
  return null;
3560
4355
  }