@resolveio/server-lib 20.14.44 → 20.14.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fixtures/cron-jobs.js +20 -3
- package/fixtures/cron-jobs.js.map +1 -1
- package/managers/subscription.manager.d.ts +2 -0
- package/managers/subscription.manager.js +16 -0
- package/managers/subscription.manager.js.map +1 -1
- package/methods/ai-terminal.d.ts +28 -1
- package/methods/ai-terminal.js +671 -73
- package/methods/ai-terminal.js.map +1 -1
- package/methods/cron-jobs.js +179 -0
- package/methods/cron-jobs.js.map +1 -1
- package/methods.ts +3 -0
- package/package.json +1 -1
package/methods/ai-terminal.js
CHANGED
|
@@ -101,6 +101,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
101
101
|
exports.loadAiTerminalMethods = loadAiTerminalMethods;
|
|
102
102
|
exports.executeAiAssistantMongoRead = executeAiAssistantMongoRead;
|
|
103
103
|
exports.executeAiAssistantMongoAggregate = executeAiAssistantMongoAggregate;
|
|
104
|
+
exports.extractAssistantMongoDirective = extractAssistantMongoDirective;
|
|
105
|
+
exports.serializeMongoValue = serializeMongoValue;
|
|
106
|
+
exports.flattenForTable = flattenForTable;
|
|
107
|
+
exports.buildDisplayTable = buildDisplayTable;
|
|
108
|
+
exports.formatDisplayTableMarkdown = formatDisplayTableMarkdown;
|
|
104
109
|
var fs_1 = require("fs");
|
|
105
110
|
var events_1 = require("events");
|
|
106
111
|
var os = require("os");
|
|
@@ -125,6 +130,28 @@ var DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
|
|
|
125
130
|
var DEFAULT_CODEX_TIMEOUT_MS = 180000;
|
|
126
131
|
var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
|
|
127
132
|
var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
|
|
133
|
+
var AI_ASSISTANT_TOOL_MAX_STEPS = 1;
|
|
134
|
+
var AI_ASSISTANT_DISPLAY_MAX_COLUMNS = 12;
|
|
135
|
+
var AI_ASSISTANT_DISPLAY_PREVIEW_MAX_ROWS = 20;
|
|
136
|
+
var AI_ASSISTANT_DISPLAY_STRING_LIMIT = 160;
|
|
137
|
+
var AI_ASSISTANT_DISPLAY_PRIORITY_FIELDS = [
|
|
138
|
+
'name',
|
|
139
|
+
'title',
|
|
140
|
+
'status',
|
|
141
|
+
'type',
|
|
142
|
+
'stage',
|
|
143
|
+
'state',
|
|
144
|
+
'category',
|
|
145
|
+
'date_created',
|
|
146
|
+
'createdAt',
|
|
147
|
+
'updatedAt',
|
|
148
|
+
'date_updated',
|
|
149
|
+
'date_completed',
|
|
150
|
+
'id_customer',
|
|
151
|
+
'id_client',
|
|
152
|
+
'id_user',
|
|
153
|
+
'id_invoice'
|
|
154
|
+
];
|
|
128
155
|
var AI_ASSISTANT_DATE_FALLBACKS = {
|
|
129
156
|
date_created: 'createdAt',
|
|
130
157
|
createdAt: 'date_created'
|
|
@@ -157,12 +184,29 @@ var AI_ASSISTANT_SENSITIVE_FIELDS = [
|
|
|
157
184
|
var AI_ASSISTANT_CLIENT_SCOPE_CACHE = new Map();
|
|
158
185
|
var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
159
186
|
'You are the ResolveIO in-app AI assistant running with read-only access to the codebase.',
|
|
187
|
+
'Core rules:',
|
|
160
188
|
'- Never share code or file contents. All code is proprietary.',
|
|
161
189
|
'- Do not modify files, run destructive commands, or access databases directly.',
|
|
162
|
-
'- Read-only Mongo access is allowed only via the MONGO_READ
|
|
190
|
+
'- Read-only Mongo access is allowed only via the MONGO_READ/MONGO_AGG directives (see below).',
|
|
163
191
|
'- Do not access secrets, credentials, or user data.',
|
|
164
192
|
'- 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.',
|
|
165
193
|
'- Do not assist with hacking, bypassing security, or abuse.',
|
|
194
|
+
'Accuracy & tools:',
|
|
195
|
+
'- 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.',
|
|
196
|
+
'- Prefer running a small Mongo read over asking multiple questions.',
|
|
197
|
+
'- Ask at most one clarifying question only when required to run a query or resolve missing details.',
|
|
198
|
+
'- Use the codebase context to choose correct collections/fields/workflows and use MONGO_READ/MONGO_AGG to answer with real data when needed.',
|
|
199
|
+
'- For direct questions, answer first. Ask a single follow-up only if required to proceed.',
|
|
200
|
+
'Data Presentation:',
|
|
201
|
+
'- Output plain Markdown (NO triple backticks).',
|
|
202
|
+
'- When you reference database results, summarize first, then include a Markdown table.',
|
|
203
|
+
'- When presenting record lists or aggregates, produce a Markdown table (pipes).',
|
|
204
|
+
'- Never show raw JSON dumps.',
|
|
205
|
+
'- Do not include `_id` & `__v` & `id_<other collection _id property>` in tables by default.',
|
|
206
|
+
'- 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.',
|
|
207
|
+
'- Rename `createdAt` to `Created At` and `updatedAt` to `Updated At` in tables.',
|
|
208
|
+
'Response style:',
|
|
209
|
+
'- Keep responses concise: answer first, then 3-8 bullets, then a table when data is involved.',
|
|
166
210
|
'- Prefer high-level explanations and point to routes instead of code. Only mention file paths if explicitly requested.',
|
|
167
211
|
'- 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.',
|
|
168
212
|
'- When asked "why is this happening," respond with: cause, trigger, data source(s), and expected vs actual outcome.',
|
|
@@ -174,7 +218,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
174
218
|
'- If access is blocked, name the permission/role needed and how to request it.',
|
|
175
219
|
'- Avoid vague labels like "Operations app"; use the specific screen/workflow name.',
|
|
176
220
|
'- Do not mention other client projects or ask which client; stay within the current project context.',
|
|
177
|
-
'-
|
|
221
|
+
'- Do not add labels like "Customer-facing summary" or "Work ticket summary" and do not include estimated hours.',
|
|
178
222
|
'- Use structured responses by default: short heading, then bullet points. For "how do I" questions, provide a step-by-step list (numbered) with explicit page/screen names and actions.',
|
|
179
223
|
'- When giving steps, include navigation guidance like "Go to <screen>" and "Click/Select/Enter <field>" so the user can follow it exactly.',
|
|
180
224
|
'- If context scope is provided (ex: current page), prioritize that screen in your answer.',
|
|
@@ -183,8 +227,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
183
227
|
'- SUPPORT_TICKET_CREATE: <one-line summary>',
|
|
184
228
|
'- Only include that line when the user clearly wants a ticket created. Do not claim a ticket is created unless you include that line.',
|
|
185
229
|
'- Do not end responses with tentative phrasing like "I could" or "I’m going to." Complete the request or state what is required to proceed.',
|
|
186
|
-
'
|
|
187
|
-
'- For direct questions, answer first. Ask a single follow-up only if required to run a query or resolve missing details.',
|
|
230
|
+
'Mongo directives:',
|
|
188
231
|
'- If you need database data to answer, end your response with a single line exactly in this format:',
|
|
189
232
|
'- MONGO_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
|
|
190
233
|
'- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
|
|
@@ -199,7 +242,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
199
242
|
'- For creation-date questions when both date_created and createdAt exist, match both with $or so results are not missed.',
|
|
200
243
|
'- When grouping by fields that can be arrays (drivers, deliveries, routes, chemicals), $unwind first and group by both id and name when available.',
|
|
201
244
|
'- Use MONGO_READ/MONGO_AGG only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
|
|
202
|
-
'-
|
|
245
|
+
'- If the user explicitly asks for IDs, set options.includeIds: true.',
|
|
203
246
|
'- Keep responses concise and use low reasoning effort.'
|
|
204
247
|
].join('\n');
|
|
205
248
|
var AI_FORM_PATCH_SYSTEM_PROMPT = [
|
|
@@ -738,10 +781,10 @@ function executeAiFormPatch(payload, context) {
|
|
|
738
781
|
}
|
|
739
782
|
function executeAiAssistantCodexRun(payload, context) {
|
|
740
783
|
return __awaiter(this, void 0, void 0, function () {
|
|
741
|
-
var input, message, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, prompt, workspaceRoot, codexConfig, runOptions, responseText, assistantContent, userDoc, assistantDoc, insertResult;
|
|
742
|
-
var
|
|
743
|
-
return __generator(this, function (
|
|
744
|
-
switch (
|
|
784
|
+
var input, message, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, assistantContext, prompt, workspaceRoot, codexConfig, runOptions, responseText, directive, cleanedResponseText, assistantContent, toolResult, toolRequest, toolResponse, _b, toolPayload, followupPrompt, followupText, _c, error_1, userDoc, assistantDoc, insertResult;
|
|
785
|
+
var _d, _e;
|
|
786
|
+
return __generator(this, function (_f) {
|
|
787
|
+
switch (_f.label) {
|
|
745
788
|
case 0:
|
|
746
789
|
input = payload || {};
|
|
747
790
|
message = normalizeOptionalString(input.message);
|
|
@@ -755,7 +798,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
755
798
|
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
|
|
756
799
|
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
757
800
|
case 1:
|
|
758
|
-
conversation_2 =
|
|
801
|
+
conversation_2 = _f.sent();
|
|
759
802
|
now_2 = new Date();
|
|
760
803
|
userMsg = {
|
|
761
804
|
id_conversation: conversation_2._id,
|
|
@@ -777,13 +820,13 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
777
820
|
};
|
|
778
821
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userMsg)];
|
|
779
822
|
case 2:
|
|
780
|
-
|
|
823
|
+
_f.sent();
|
|
781
824
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantMsg)];
|
|
782
825
|
case 3:
|
|
783
|
-
|
|
826
|
+
_f.sent();
|
|
784
827
|
return [4 /*yield*/, touchConversation(conversation_2._id, now_2)];
|
|
785
828
|
case 4:
|
|
786
|
-
|
|
829
|
+
_f.sent();
|
|
787
830
|
return [2 /*return*/, {
|
|
788
831
|
conversation: conversation_2,
|
|
789
832
|
message: assistantMsg,
|
|
@@ -791,27 +834,27 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
791
834
|
}];
|
|
792
835
|
case 5: return [4 /*yield*/, user_collection_1.Users.findById(context === null || context === void 0 ? void 0 : context.id_user)];
|
|
793
836
|
case 6:
|
|
794
|
-
user =
|
|
795
|
-
isSuperAdmin = !!((
|
|
837
|
+
user = _f.sent();
|
|
838
|
+
isSuperAdmin = !!((_d = user === null || user === void 0 ? void 0 : user.roles) === null || _d === void 0 ? void 0 : _d.super_admin);
|
|
796
839
|
hasInvoiceAccess = userHasInvoiceAccess(user);
|
|
797
|
-
customerId = normalizeOptionalString((
|
|
840
|
+
customerId = normalizeOptionalString((_e = user === null || user === void 0 ? void 0 : user.other) === null || _e === void 0 ? void 0 : _e.id_customer);
|
|
798
841
|
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
799
842
|
case 7:
|
|
800
|
-
conversation =
|
|
843
|
+
conversation = _f.sent();
|
|
801
844
|
now = new Date();
|
|
802
845
|
attachments = Array.isArray(input.attachments) ? input.attachments : [];
|
|
803
846
|
return [4 /*yield*/, readAttachmentContents(attachments)];
|
|
804
847
|
case 8:
|
|
805
|
-
attachmentData =
|
|
848
|
+
attachmentData = _f.sent();
|
|
806
849
|
historyLimit = normalizeHistoryLimit(input.max_history);
|
|
807
850
|
if (!(historyLimit > 0)) return [3 /*break*/, 10];
|
|
808
851
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find({ id_conversation: conversation._id, role: { $in: ['user', 'assistant'] } }, { sort: { createdAt: 1 }, limit: historyLimit * 2 })];
|
|
809
852
|
case 9:
|
|
810
|
-
_a =
|
|
853
|
+
_a = _f.sent();
|
|
811
854
|
return [3 /*break*/, 11];
|
|
812
855
|
case 10:
|
|
813
856
|
_a = [];
|
|
814
|
-
|
|
857
|
+
_f.label = 11;
|
|
815
858
|
case 11:
|
|
816
859
|
history = _a;
|
|
817
860
|
historyLines = [];
|
|
@@ -822,10 +865,11 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
822
865
|
historyLines.push("".concat(role, ": ").concat(content));
|
|
823
866
|
}
|
|
824
867
|
});
|
|
825
|
-
|
|
868
|
+
assistantContext = buildAssistantContext(input, { isSuperAdmin: isSuperAdmin, hasInvoiceAccess: hasInvoiceAccess, customerId: customerId });
|
|
869
|
+
prompt = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
|
|
826
870
|
return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
|
|
827
871
|
case 12:
|
|
828
|
-
workspaceRoot =
|
|
872
|
+
workspaceRoot = _f.sent();
|
|
829
873
|
codexConfig = resolveCodexSettings();
|
|
830
874
|
runOptions = {
|
|
831
875
|
timeoutMs: resolveCodexTimeoutMs(),
|
|
@@ -842,8 +886,48 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
842
886
|
};
|
|
843
887
|
return [4 /*yield*/, runCodexInWorkerThread(prompt, runOptions, codexConfig)];
|
|
844
888
|
case 13:
|
|
845
|
-
responseText =
|
|
846
|
-
|
|
889
|
+
responseText = _f.sent();
|
|
890
|
+
directive = extractAssistantMongoDirective(responseText);
|
|
891
|
+
cleanedResponseText = (directive === null || directive === void 0 ? void 0 : directive.cleaned) || responseText;
|
|
892
|
+
assistantContent = sanitizeAssistantResponse(cleanedResponseText);
|
|
893
|
+
toolResult = null;
|
|
894
|
+
if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 24];
|
|
895
|
+
toolRequest = buildAssistantToolRequest(directive, input);
|
|
896
|
+
_f.label = 14;
|
|
897
|
+
case 14:
|
|
898
|
+
_f.trys.push([14, 23, , 24]);
|
|
899
|
+
if (!(directive.type === 'aggregate')) return [3 /*break*/, 16];
|
|
900
|
+
return [4 /*yield*/, executeAiAssistantMongoAggregate(toolRequest, context)];
|
|
901
|
+
case 15:
|
|
902
|
+
_b = _f.sent();
|
|
903
|
+
return [3 /*break*/, 18];
|
|
904
|
+
case 16: return [4 /*yield*/, executeAiAssistantMongoRead(toolRequest, context)];
|
|
905
|
+
case 17:
|
|
906
|
+
_b = _f.sent();
|
|
907
|
+
_f.label = 18;
|
|
908
|
+
case 18:
|
|
909
|
+
toolResponse = _b;
|
|
910
|
+
toolPayload = buildAssistantToolResultPayload(directive, toolResponse);
|
|
911
|
+
toolResult = toolPayload.result;
|
|
912
|
+
followupPrompt = buildAssistantCodexToolFollowupPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, toolPayload.prompt);
|
|
913
|
+
_f.label = 19;
|
|
914
|
+
case 19:
|
|
915
|
+
_f.trys.push([19, 21, , 22]);
|
|
916
|
+
return [4 /*yield*/, runCodexInWorkerThread(followupPrompt, runOptions, codexConfig)];
|
|
917
|
+
case 20:
|
|
918
|
+
followupText = _f.sent();
|
|
919
|
+
assistantContent = sanitizeAssistantResponse(followupText);
|
|
920
|
+
return [3 /*break*/, 22];
|
|
921
|
+
case 21:
|
|
922
|
+
_c = _f.sent();
|
|
923
|
+
assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
|
|
924
|
+
return [3 /*break*/, 22];
|
|
925
|
+
case 22: return [3 /*break*/, 24];
|
|
926
|
+
case 23:
|
|
927
|
+
error_1 = _f.sent();
|
|
928
|
+
assistantContent = buildAssistantToolErrorMessage(error_1, directive, toolRequest);
|
|
929
|
+
return [3 /*break*/, 24];
|
|
930
|
+
case 24:
|
|
847
931
|
userDoc = {
|
|
848
932
|
id_conversation: conversation._id,
|
|
849
933
|
role: 'user',
|
|
@@ -862,34 +946,34 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
862
946
|
createdAt: now,
|
|
863
947
|
updatedAt: now
|
|
864
948
|
};
|
|
949
|
+
if (toolResult) {
|
|
950
|
+
assistantDoc.metadata = __assign(__assign({}, (assistantDoc.metadata || {})), { tool_result: toolResult });
|
|
951
|
+
}
|
|
865
952
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
|
|
866
|
-
case
|
|
867
|
-
|
|
953
|
+
case 25:
|
|
954
|
+
_f.sent();
|
|
868
955
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
|
|
869
|
-
case
|
|
870
|
-
insertResult =
|
|
956
|
+
case 26:
|
|
957
|
+
insertResult = _f.sent();
|
|
871
958
|
return [4 /*yield*/, touchConversation(conversation._id, now, insertResult._id)];
|
|
872
|
-
case
|
|
873
|
-
|
|
874
|
-
if (!(input.delete_files_after_run !== false)) return [3 /*break*/,
|
|
959
|
+
case 27:
|
|
960
|
+
_f.sent();
|
|
961
|
+
if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 29];
|
|
875
962
|
return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
|
|
876
|
-
case
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
case
|
|
880
|
-
conversation: conversation,
|
|
881
|
-
message: assistantDoc
|
|
882
|
-
}];
|
|
963
|
+
case 28:
|
|
964
|
+
_f.sent();
|
|
965
|
+
_f.label = 29;
|
|
966
|
+
case 29: return [2 /*return*/, __assign({ conversation: conversation, message: assistantDoc }, (toolResult ? { tool_result: toolResult } : {}))];
|
|
883
967
|
}
|
|
884
968
|
});
|
|
885
969
|
});
|
|
886
970
|
}
|
|
887
971
|
function executeAiAssistantMongoRead(payload, context) {
|
|
888
972
|
return __awaiter(this, void 0, void 0, function () {
|
|
889
|
-
var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalized, documents, total, sanitizedDocuments;
|
|
890
|
-
var _c;
|
|
891
|
-
return __generator(this, function (
|
|
892
|
-
switch (
|
|
973
|
+
var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalized, documents, total, sanitizedDocuments, includeIds, display;
|
|
974
|
+
var _c, _d;
|
|
975
|
+
return __generator(this, function (_e) {
|
|
976
|
+
switch (_e.label) {
|
|
893
977
|
case 0:
|
|
894
978
|
input = payload || {};
|
|
895
979
|
collection = normalizeOptionalString(input.collection);
|
|
@@ -898,7 +982,7 @@ function executeAiAssistantMongoRead(payload, context) {
|
|
|
898
982
|
}
|
|
899
983
|
return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
|
|
900
984
|
case 1:
|
|
901
|
-
_a =
|
|
985
|
+
_a = _e.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
|
|
902
986
|
if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
|
|
903
987
|
throw new Error('AI assistant mongo read: Access denied.');
|
|
904
988
|
}
|
|
@@ -919,11 +1003,11 @@ function executeAiAssistantMongoRead(payload, context) {
|
|
|
919
1003
|
if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
|
|
920
1004
|
return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
|
|
921
1005
|
case 2:
|
|
922
|
-
_b =
|
|
1006
|
+
_b = _e.sent();
|
|
923
1007
|
return [3 /*break*/, 4];
|
|
924
1008
|
case 3:
|
|
925
1009
|
_b = false;
|
|
926
|
-
|
|
1010
|
+
_e.label = 4;
|
|
927
1011
|
case 4:
|
|
928
1012
|
shouldScopeByClient = _b;
|
|
929
1013
|
clientScopedQuery = shouldScopeByClient
|
|
@@ -933,18 +1017,27 @@ function executeAiAssistantMongoRead(payload, context) {
|
|
|
933
1017
|
normalized = normalizeAssistantFindOptions(input.options);
|
|
934
1018
|
return [4 /*yield*/, db.collection(collection).find(scopedQuery, normalized.findOptions).toArray()];
|
|
935
1019
|
case 5:
|
|
936
|
-
documents =
|
|
1020
|
+
documents = _e.sent();
|
|
937
1021
|
total = null;
|
|
938
1022
|
if (!normalized.includeTotal) return [3 /*break*/, 7];
|
|
939
1023
|
return [4 /*yield*/, db.collection(collection).countDocuments(scopedQuery)];
|
|
940
1024
|
case 6:
|
|
941
|
-
total =
|
|
942
|
-
|
|
1025
|
+
total = _e.sent();
|
|
1026
|
+
_e.label = 7;
|
|
943
1027
|
case 7:
|
|
944
1028
|
sanitizedDocuments = isSuperAdmin
|
|
945
1029
|
? documents
|
|
946
1030
|
: documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
|
|
947
|
-
|
|
1031
|
+
includeIds = ((_d = input.options) === null || _d === void 0 ? void 0 : _d.includeIds) === true;
|
|
1032
|
+
display = buildDisplayTable(sanitizedDocuments, {
|
|
1033
|
+
includeIds: includeIds,
|
|
1034
|
+
maxColumns: AI_ASSISTANT_DISPLAY_MAX_COLUMNS,
|
|
1035
|
+
maxRows: normalized.findOptions.limit
|
|
1036
|
+
});
|
|
1037
|
+
if (total !== null) {
|
|
1038
|
+
display.total = total;
|
|
1039
|
+
}
|
|
1040
|
+
return [2 /*return*/, __assign({ documents: sanitizedDocuments, total: total, display: display }, (isSuperAdmin ? {
|
|
948
1041
|
debug: {
|
|
949
1042
|
collection: collection,
|
|
950
1043
|
database: dbName,
|
|
@@ -959,10 +1052,10 @@ function executeAiAssistantMongoRead(payload, context) {
|
|
|
959
1052
|
}
|
|
960
1053
|
function executeAiAssistantMongoAggregate(payload, context) {
|
|
961
1054
|
return __awaiter(this, void 0, void 0, function () {
|
|
962
|
-
var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, documents, executedPipeline, fallbackMeta, fallback, fallbackPipeline, fallbackDocs, unwindFallback, fallbackPipeline, fallbackDocs, sanitizedDocuments;
|
|
963
|
-
var _c;
|
|
964
|
-
return __generator(this, function (
|
|
965
|
-
switch (
|
|
1055
|
+
var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, documents, executedPipeline, fallbackMeta, fallback, fallbackPipeline, fallbackDocs, unwindFallback, fallbackPipeline, fallbackDocs, sanitizedDocuments, includeIds, display;
|
|
1056
|
+
var _c, _d;
|
|
1057
|
+
return __generator(this, function (_e) {
|
|
1058
|
+
switch (_e.label) {
|
|
966
1059
|
case 0:
|
|
967
1060
|
input = payload || {};
|
|
968
1061
|
collection = normalizeOptionalString(input.collection);
|
|
@@ -971,7 +1064,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
971
1064
|
}
|
|
972
1065
|
return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
|
|
973
1066
|
case 1:
|
|
974
|
-
_a =
|
|
1067
|
+
_a = _e.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
|
|
975
1068
|
if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
|
|
976
1069
|
throw new Error('AI assistant mongo aggregate: Access denied.');
|
|
977
1070
|
}
|
|
@@ -992,11 +1085,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
992
1085
|
if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
|
|
993
1086
|
return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
|
|
994
1087
|
case 2:
|
|
995
|
-
_b =
|
|
1088
|
+
_b = _e.sent();
|
|
996
1089
|
return [3 /*break*/, 4];
|
|
997
1090
|
case 3:
|
|
998
1091
|
_b = false;
|
|
999
|
-
|
|
1092
|
+
_e.label = 4;
|
|
1000
1093
|
case 4:
|
|
1001
1094
|
shouldScopeByClient = _b;
|
|
1002
1095
|
clientScopedQuery = shouldScopeByClient
|
|
@@ -1014,7 +1107,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
1014
1107
|
.aggregate(limitedPipeline, normalizedOptions.aggregateOptions)
|
|
1015
1108
|
.toArray()];
|
|
1016
1109
|
case 5:
|
|
1017
|
-
documents =
|
|
1110
|
+
documents = _e.sent();
|
|
1018
1111
|
executedPipeline = limitedPipeline;
|
|
1019
1112
|
fallbackMeta = {};
|
|
1020
1113
|
if (!!documents.length) return [3 /*break*/, 7];
|
|
@@ -1027,13 +1120,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
1027
1120
|
.aggregate(fallbackPipeline, normalizedOptions.aggregateOptions)
|
|
1028
1121
|
.toArray()];
|
|
1029
1122
|
case 6:
|
|
1030
|
-
fallbackDocs =
|
|
1123
|
+
fallbackDocs = _e.sent();
|
|
1031
1124
|
if (fallbackDocs.length) {
|
|
1032
1125
|
documents = fallbackDocs;
|
|
1033
1126
|
executedPipeline = fallbackPipeline;
|
|
1034
1127
|
fallbackMeta.dateField.used = true;
|
|
1035
1128
|
}
|
|
1036
|
-
|
|
1129
|
+
_e.label = 7;
|
|
1037
1130
|
case 7:
|
|
1038
1131
|
if (!(documents.length <= 1)) return [3 /*break*/, 9];
|
|
1039
1132
|
unwindFallback = resolveAggregateUnwindFallback(executedPipeline);
|
|
@@ -1045,18 +1138,24 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
1045
1138
|
.aggregate(fallbackPipeline, normalizedOptions.aggregateOptions)
|
|
1046
1139
|
.toArray()];
|
|
1047
1140
|
case 8:
|
|
1048
|
-
fallbackDocs =
|
|
1141
|
+
fallbackDocs = _e.sent();
|
|
1049
1142
|
if (fallbackDocs.length > documents.length) {
|
|
1050
1143
|
documents = fallbackDocs;
|
|
1051
1144
|
executedPipeline = fallbackPipeline;
|
|
1052
1145
|
fallbackMeta.unwind.used = true;
|
|
1053
1146
|
}
|
|
1054
|
-
|
|
1147
|
+
_e.label = 9;
|
|
1055
1148
|
case 9:
|
|
1056
1149
|
sanitizedDocuments = isSuperAdmin
|
|
1057
1150
|
? documents
|
|
1058
1151
|
: documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
|
|
1059
|
-
|
|
1152
|
+
includeIds = ((_d = input.options) === null || _d === void 0 ? void 0 : _d.includeIds) === true;
|
|
1153
|
+
display = buildDisplayTable(sanitizedDocuments, {
|
|
1154
|
+
includeIds: includeIds,
|
|
1155
|
+
maxColumns: AI_ASSISTANT_DISPLAY_MAX_COLUMNS,
|
|
1156
|
+
maxRows: normalizedOptions.limit || sanitizedDocuments.length
|
|
1157
|
+
});
|
|
1158
|
+
return [2 /*return*/, __assign({ documents: sanitizedDocuments, display: display }, (isSuperAdmin ? {
|
|
1060
1159
|
debug: {
|
|
1061
1160
|
collection: collection,
|
|
1062
1161
|
database: dbName,
|
|
@@ -1071,6 +1170,478 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
1071
1170
|
});
|
|
1072
1171
|
});
|
|
1073
1172
|
}
|
|
1173
|
+
function extractAssistantMongoDirective(content) {
|
|
1174
|
+
var lines = String(content || '').split('\n');
|
|
1175
|
+
var directiveIndex = -1;
|
|
1176
|
+
var directiveLine = '';
|
|
1177
|
+
var directiveType = null;
|
|
1178
|
+
var directiveIndexes = new Set();
|
|
1179
|
+
lines.forEach(function (line, index) {
|
|
1180
|
+
var normalized = line.trim().replace(/^[-*]+\s*/, '');
|
|
1181
|
+
var upper = normalized.toUpperCase();
|
|
1182
|
+
if (upper.startsWith('MONGO_READ:')) {
|
|
1183
|
+
directiveIndexes.add(index);
|
|
1184
|
+
directiveIndex = index;
|
|
1185
|
+
directiveLine = normalized;
|
|
1186
|
+
directiveType = 'read';
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
if (upper.startsWith('MONGO_AGG:') || upper.startsWith('MONGO_AGGREGATE:')) {
|
|
1190
|
+
directiveIndexes.add(index);
|
|
1191
|
+
directiveIndex = index;
|
|
1192
|
+
directiveLine = normalized;
|
|
1193
|
+
directiveType = 'aggregate';
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
if (directiveIndex === -1 || !directiveType) {
|
|
1197
|
+
return null;
|
|
1198
|
+
}
|
|
1199
|
+
var colonIndex = directiveLine.indexOf(':');
|
|
1200
|
+
var after = colonIndex >= 0 ? directiveLine.slice(colonIndex + 1).trim() : '';
|
|
1201
|
+
var parsed = after ? parseJsonObject(after) : null;
|
|
1202
|
+
var payload = parsed && typeof parsed === 'object' ? parsed : null;
|
|
1203
|
+
var cleaned = lines.filter(function (_, index) { return !directiveIndexes.has(index); }).join('\n').trim();
|
|
1204
|
+
return {
|
|
1205
|
+
type: directiveType,
|
|
1206
|
+
payload: payload,
|
|
1207
|
+
cleaned: cleaned,
|
|
1208
|
+
rawLine: directiveLine
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
function buildAssistantToolRequest(directive, payload) {
|
|
1212
|
+
var _a;
|
|
1213
|
+
var base = directive.payload && typeof directive.payload === 'object' ? directive.payload : {};
|
|
1214
|
+
var request = __assign({}, base);
|
|
1215
|
+
var route = normalizeOptionalString((_a = payload === null || payload === void 0 ? void 0 : payload.context) === null || _a === void 0 ? void 0 : _a.route);
|
|
1216
|
+
if (!request.permissionView && route) {
|
|
1217
|
+
request.permissionView = route;
|
|
1218
|
+
}
|
|
1219
|
+
if (!request.id_client) {
|
|
1220
|
+
var idClient = normalizeOptionalString(payload === null || payload === void 0 ? void 0 : payload.id_client);
|
|
1221
|
+
if (idClient) {
|
|
1222
|
+
request.id_client = idClient;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
if (!request.mongo && (payload === null || payload === void 0 ? void 0 : payload.mongo)) {
|
|
1226
|
+
request.mongo = payload.mongo;
|
|
1227
|
+
}
|
|
1228
|
+
return request;
|
|
1229
|
+
}
|
|
1230
|
+
function buildAssistantToolResultPayload(directive, toolResponse) {
|
|
1231
|
+
var _a;
|
|
1232
|
+
var directivePayload = directive.payload || {};
|
|
1233
|
+
var documents = Array.isArray(toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.documents) ? toolResponse.documents : [];
|
|
1234
|
+
var includeIds = ((_a = directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.options) === null || _a === void 0 ? void 0 : _a.includeIds) === true;
|
|
1235
|
+
var display = (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.display) && typeof toolResponse.display === 'object'
|
|
1236
|
+
? toolResponse.display
|
|
1237
|
+
: buildDisplayTable(documents, {
|
|
1238
|
+
includeIds: includeIds,
|
|
1239
|
+
maxColumns: AI_ASSISTANT_DISPLAY_MAX_COLUMNS,
|
|
1240
|
+
maxRows: AI_ASSISTANT_DISPLAY_PREVIEW_MAX_ROWS
|
|
1241
|
+
});
|
|
1242
|
+
var trimmedDisplay = trimDisplayTable(display, {
|
|
1243
|
+
maxColumns: AI_ASSISTANT_DISPLAY_MAX_COLUMNS,
|
|
1244
|
+
maxRows: AI_ASSISTANT_DISPLAY_PREVIEW_MAX_ROWS
|
|
1245
|
+
});
|
|
1246
|
+
var total = typeof (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.total) === 'number' ? toolResponse.total : null;
|
|
1247
|
+
var rowCount = documents.length || trimmedDisplay.rowCount;
|
|
1248
|
+
var collection = normalizeOptionalString(directivePayload === null || directivePayload === void 0 ? void 0 : directivePayload.collection) || '';
|
|
1249
|
+
var result = {
|
|
1250
|
+
type: directive.type === 'aggregate' ? 'mongo_agg' : 'mongo_read',
|
|
1251
|
+
input: directivePayload,
|
|
1252
|
+
output: {
|
|
1253
|
+
display: trimmedDisplay,
|
|
1254
|
+
total: total !== null ? total : undefined,
|
|
1255
|
+
collection: collection || undefined,
|
|
1256
|
+
rowCount: rowCount,
|
|
1257
|
+
columns: trimmedDisplay.columns,
|
|
1258
|
+
truncated: trimmedDisplay.truncated
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
return {
|
|
1262
|
+
result: result,
|
|
1263
|
+
prompt: buildAssistantToolResultPrompt(result)
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
function buildAssistantToolResultPrompt(result) {
|
|
1267
|
+
var _a, _b;
|
|
1268
|
+
var lines = ['Tool Result:'];
|
|
1269
|
+
lines.push("Type: ".concat(result.type));
|
|
1270
|
+
if (result.output.collection) {
|
|
1271
|
+
lines.push("Collection: ".concat(result.output.collection));
|
|
1272
|
+
}
|
|
1273
|
+
lines.push("Row count: ".concat(result.output.rowCount));
|
|
1274
|
+
if (typeof result.output.total === 'number') {
|
|
1275
|
+
lines.push("Total: ".concat(result.output.total));
|
|
1276
|
+
}
|
|
1277
|
+
if (Array.isArray(result.output.columns) && result.output.columns.length) {
|
|
1278
|
+
lines.push("Columns: ".concat(result.output.columns.join(', ')));
|
|
1279
|
+
}
|
|
1280
|
+
if ((_b = (_a = result.output.display) === null || _a === void 0 ? void 0 : _a.rows) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1281
|
+
lines.push('Preview:');
|
|
1282
|
+
lines.push(formatDisplayTableMarkdown(result.output.display));
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
lines.push('Preview: (no rows)');
|
|
1286
|
+
}
|
|
1287
|
+
return lines.join('\n');
|
|
1288
|
+
}
|
|
1289
|
+
function buildAssistantCodexToolFollowupPrompt(message, attachmentText, historyText, contextText, toolResultText) {
|
|
1290
|
+
var trimmedContext = normalizeOptionalString(contextText);
|
|
1291
|
+
var contextBlock = trimmedContext ? "\n\nContext:\n".concat(trimmedContext) : '';
|
|
1292
|
+
var trimmedHistory = normalizeOptionalString(historyText);
|
|
1293
|
+
var historyBlock = trimmedHistory ? "\n\nConversation so far:\n".concat(trimmedHistory) : '';
|
|
1294
|
+
var toolBlock = toolResultText ? "\n\nTool Result:\n".concat(toolResultText) : '';
|
|
1295
|
+
var instruction = '\n\nInstruction:\nNow answer the user. Do NOT output another MONGO_* directive. Output plain Markdown. Summarize first, then include a Markdown table.';
|
|
1296
|
+
return "System:\n".concat(AI_ASSISTANT_SYSTEM_PROMPT).concat(contextBlock).concat(historyBlock, "\n\nUser:\n").concat(message).concat(attachmentText || '').concat(toolBlock).concat(instruction).trim();
|
|
1297
|
+
}
|
|
1298
|
+
function buildAssistantToolFallbackResponse(result) {
|
|
1299
|
+
var _a, _b;
|
|
1300
|
+
var lines = ['Here is a data snapshot based on the tool result:'];
|
|
1301
|
+
if (result.output.collection) {
|
|
1302
|
+
lines.push("- Collection: ".concat(result.output.collection));
|
|
1303
|
+
}
|
|
1304
|
+
lines.push("- Rows returned: ".concat(result.output.rowCount));
|
|
1305
|
+
if (typeof result.output.total === 'number') {
|
|
1306
|
+
lines.push("- Total: ".concat(result.output.total));
|
|
1307
|
+
}
|
|
1308
|
+
if ((_b = (_a = result.output.display) === null || _a === void 0 ? void 0 : _a.rows) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1309
|
+
lines.push('');
|
|
1310
|
+
lines.push(formatDisplayTableMarkdown(result.output.display));
|
|
1311
|
+
}
|
|
1312
|
+
return lines.join('\n').trim();
|
|
1313
|
+
}
|
|
1314
|
+
function buildAssistantToolErrorMessage(error, directive, request) {
|
|
1315
|
+
var _a, _b;
|
|
1316
|
+
var rawMessage = normalizeOptionalString(error === null || error === void 0 ? void 0 : error.message) || 'Unable to access data.';
|
|
1317
|
+
var normalized = rawMessage.toLowerCase();
|
|
1318
|
+
var routeHint = normalizeOptionalString(request === null || request === void 0 ? void 0 : request.permissionView)
|
|
1319
|
+
|| normalizeOptionalString((_a = directive.payload) === null || _a === void 0 ? void 0 : _a.permissionView);
|
|
1320
|
+
var collection = normalizeOptionalString(request === null || request === void 0 ? void 0 : request.collection) || normalizeOptionalString((_b = directive.payload) === null || _b === void 0 ? void 0 : _b.collection);
|
|
1321
|
+
var routeLine = routeHint
|
|
1322
|
+
? "Open ".concat(routeHint, " in the app to view this data or request access.")
|
|
1323
|
+
: 'Open the related screen in the app to view this data or request access.';
|
|
1324
|
+
if (!routeHint && collection && requiresInvoicePermission(collection)) {
|
|
1325
|
+
routeLine = 'Open /invoice/list or /report/invoice to view this data or request access.';
|
|
1326
|
+
}
|
|
1327
|
+
if (normalized.includes('permission scope required')) {
|
|
1328
|
+
return "I need a permission scope to access that data. ".concat(routeLine);
|
|
1329
|
+
}
|
|
1330
|
+
if (normalized.includes('access denied')) {
|
|
1331
|
+
if (collection && requiresInvoicePermission(collection)) {
|
|
1332
|
+
return "Invoice access is required to view that data. ".concat(routeLine);
|
|
1333
|
+
}
|
|
1334
|
+
return "You don't have permission to view that data. ".concat(routeLine);
|
|
1335
|
+
}
|
|
1336
|
+
if (normalized.includes('database access denied')) {
|
|
1337
|
+
return "Database access is restricted for that request. ".concat(routeLine);
|
|
1338
|
+
}
|
|
1339
|
+
if (normalized.includes('collection is required')) {
|
|
1340
|
+
return 'I need a valid collection to read from. Please specify which screen or dataset you want.';
|
|
1341
|
+
}
|
|
1342
|
+
return "I couldn't access the requested data. ".concat(routeLine);
|
|
1343
|
+
}
|
|
1344
|
+
function isAssistantIdField(key) {
|
|
1345
|
+
var normalized = String(key || '').trim().toLowerCase();
|
|
1346
|
+
if (!normalized) {
|
|
1347
|
+
return false;
|
|
1348
|
+
}
|
|
1349
|
+
if (normalized === '_id' || normalized === '__v') {
|
|
1350
|
+
return true;
|
|
1351
|
+
}
|
|
1352
|
+
if (normalized.startsWith('id_')) {
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1355
|
+
var parts = normalized.split('.');
|
|
1356
|
+
var last = parts[parts.length - 1] || '';
|
|
1357
|
+
return last.startsWith('id_');
|
|
1358
|
+
}
|
|
1359
|
+
function isMongoObjectId(value) {
|
|
1360
|
+
if (!value || typeof value !== 'object') {
|
|
1361
|
+
return false;
|
|
1362
|
+
}
|
|
1363
|
+
if (typeof value.toHexString === 'function') {
|
|
1364
|
+
return true;
|
|
1365
|
+
}
|
|
1366
|
+
return value._bsontype === 'ObjectId';
|
|
1367
|
+
}
|
|
1368
|
+
function isPlainObject(value) {
|
|
1369
|
+
return !!value && typeof value === 'object' && Object.prototype.toString.call(value) === '[object Object]';
|
|
1370
|
+
}
|
|
1371
|
+
function normalizeColumnPriorityKey(column) {
|
|
1372
|
+
var trimmed = String(column || '').trim();
|
|
1373
|
+
if (!trimmed) {
|
|
1374
|
+
return '';
|
|
1375
|
+
}
|
|
1376
|
+
var base = trimmed.includes('.') ? trimmed.split('.').pop() || trimmed : trimmed;
|
|
1377
|
+
return base.toLowerCase();
|
|
1378
|
+
}
|
|
1379
|
+
function formatDisplayColumnName(column) {
|
|
1380
|
+
var trimmed = String(column || '').trim();
|
|
1381
|
+
if (!trimmed) {
|
|
1382
|
+
return '';
|
|
1383
|
+
}
|
|
1384
|
+
if (trimmed === '_id') {
|
|
1385
|
+
return 'id';
|
|
1386
|
+
}
|
|
1387
|
+
if (trimmed === '_group') {
|
|
1388
|
+
return 'Group';
|
|
1389
|
+
}
|
|
1390
|
+
var normalized = trimmed.replace(/[\s_]+/g, '').toLowerCase();
|
|
1391
|
+
if (normalized === 'createdat') {
|
|
1392
|
+
return 'Created At';
|
|
1393
|
+
}
|
|
1394
|
+
if (normalized === 'updatedat') {
|
|
1395
|
+
return 'Updated At';
|
|
1396
|
+
}
|
|
1397
|
+
return trimmed;
|
|
1398
|
+
}
|
|
1399
|
+
function truncateDisplayText(value, maxLength) {
|
|
1400
|
+
if (maxLength === void 0) { maxLength = AI_ASSISTANT_DISPLAY_STRING_LIMIT; }
|
|
1401
|
+
if (!value) {
|
|
1402
|
+
return value;
|
|
1403
|
+
}
|
|
1404
|
+
if (value.length <= maxLength) {
|
|
1405
|
+
return value;
|
|
1406
|
+
}
|
|
1407
|
+
var sliceLength = Math.max(0, maxLength - 3);
|
|
1408
|
+
return "".concat(value.slice(0, sliceLength), "...");
|
|
1409
|
+
}
|
|
1410
|
+
function serializeMongoValue(value, maxLength) {
|
|
1411
|
+
if (maxLength === void 0) { maxLength = AI_ASSISTANT_DISPLAY_STRING_LIMIT; }
|
|
1412
|
+
if (value === null || value === undefined) {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
1416
|
+
return value;
|
|
1417
|
+
}
|
|
1418
|
+
if (typeof value === 'string') {
|
|
1419
|
+
return truncateDisplayText(value, maxLength);
|
|
1420
|
+
}
|
|
1421
|
+
if (value instanceof Date) {
|
|
1422
|
+
return value.toISOString();
|
|
1423
|
+
}
|
|
1424
|
+
if (isMongoObjectId(value)) {
|
|
1425
|
+
try {
|
|
1426
|
+
var hex = typeof value.toHexString === 'function' ? value.toHexString() : String(value);
|
|
1427
|
+
var shortened = hex.length > 8 ? hex.slice(0, 8) : hex;
|
|
1428
|
+
return truncateDisplayText(shortened, maxLength);
|
|
1429
|
+
}
|
|
1430
|
+
catch (_a) {
|
|
1431
|
+
return truncateDisplayText(String(value), maxLength);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
if (Array.isArray(value)) {
|
|
1435
|
+
var preview = value.slice(0, 3).map(function (entry) { return serializeMongoValue(entry, maxLength); });
|
|
1436
|
+
var compact = preview.map(function (entry) { return (entry === null || entry === undefined) ? '' : String(entry); }).join(', ');
|
|
1437
|
+
var suffix = value.length > 3 ? ', ...' : '';
|
|
1438
|
+
return truncateDisplayText("[".concat(compact).concat(suffix, "]"), maxLength);
|
|
1439
|
+
}
|
|
1440
|
+
if (typeof value === 'object') {
|
|
1441
|
+
var text = '';
|
|
1442
|
+
try {
|
|
1443
|
+
text = JSON.stringify(value);
|
|
1444
|
+
}
|
|
1445
|
+
catch (_b) {
|
|
1446
|
+
text = String(value);
|
|
1447
|
+
}
|
|
1448
|
+
if (!text || text === '[object Object]') {
|
|
1449
|
+
try {
|
|
1450
|
+
text = JSON.stringify(value, null, 2);
|
|
1451
|
+
}
|
|
1452
|
+
catch (_c) {
|
|
1453
|
+
text = String(value);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
return truncateDisplayText(text, maxLength);
|
|
1457
|
+
}
|
|
1458
|
+
return truncateDisplayText(String(value), maxLength);
|
|
1459
|
+
}
|
|
1460
|
+
function flattenForTable(doc) {
|
|
1461
|
+
var result = {};
|
|
1462
|
+
if (!doc || typeof doc !== 'object') {
|
|
1463
|
+
return result;
|
|
1464
|
+
}
|
|
1465
|
+
if (Object.prototype.hasOwnProperty.call(doc, '_id')) {
|
|
1466
|
+
var idValue_1 = doc._id;
|
|
1467
|
+
if (idValue_1 !== null && idValue_1 !== undefined) {
|
|
1468
|
+
if (isPlainObject(idValue_1) && !isMongoObjectId(idValue_1) && !(idValue_1 instanceof Date)) {
|
|
1469
|
+
Object.keys(idValue_1).forEach(function (key) {
|
|
1470
|
+
if (!key || Object.prototype.hasOwnProperty.call(result, key)) {
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
result[key] = idValue_1[key];
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
else if (!Object.prototype.hasOwnProperty.call(result, '_group')) {
|
|
1477
|
+
result._group = idValue_1;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
Object.keys(doc).forEach(function (key) {
|
|
1482
|
+
if (key === '_id') {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
var value = doc[key];
|
|
1486
|
+
if (value === undefined) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
if (isPlainObject(value) && !isMongoObjectId(value) && !(value instanceof Date)) {
|
|
1490
|
+
var nestedKeys = Object.keys(value);
|
|
1491
|
+
if (nestedKeys.length && nestedKeys.length <= 6) {
|
|
1492
|
+
nestedKeys.forEach(function (nestedKey) {
|
|
1493
|
+
if (!nestedKey) {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
var nestedValue = value[nestedKey];
|
|
1497
|
+
if (nestedValue === undefined) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
result["".concat(key, ".").concat(nestedKey)] = nestedValue;
|
|
1501
|
+
});
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
result[key] = value;
|
|
1506
|
+
});
|
|
1507
|
+
return result;
|
|
1508
|
+
}
|
|
1509
|
+
function buildDisplayTable(docs, options) {
|
|
1510
|
+
var rowsRaw = Array.isArray(docs) ? docs.map(function (doc) { return flattenForTable(doc); }) : [];
|
|
1511
|
+
var stats = new Map();
|
|
1512
|
+
rowsRaw.forEach(function (row) {
|
|
1513
|
+
Object.keys(row).forEach(function (key) {
|
|
1514
|
+
var value = row[key];
|
|
1515
|
+
var entry = stats.get(key) || { nonEmpty: 0, objectLike: 0 };
|
|
1516
|
+
if (!isEmptyDisplayValue(value)) {
|
|
1517
|
+
entry.nonEmpty += 1;
|
|
1518
|
+
}
|
|
1519
|
+
if (isDisplayObjectLike(value)) {
|
|
1520
|
+
entry.objectLike += 1;
|
|
1521
|
+
}
|
|
1522
|
+
stats.set(key, entry);
|
|
1523
|
+
});
|
|
1524
|
+
});
|
|
1525
|
+
var columns = Array.from(stats.keys()).filter(function (key) {
|
|
1526
|
+
var entry = stats.get(key);
|
|
1527
|
+
if (!entry || entry.nonEmpty === 0) {
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
if (!(options === null || options === void 0 ? void 0 : options.includeIds) && isAssistantIdField(key)) {
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1533
|
+
if (entry.objectLike / Math.max(entry.nonEmpty, 1) > 0.5) {
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
return true;
|
|
1537
|
+
});
|
|
1538
|
+
if (!columns.length && rowsRaw.length) {
|
|
1539
|
+
columns = Object.keys(rowsRaw[0] || {}).filter(function (key) { return (options === null || options === void 0 ? void 0 : options.includeIds) || !isAssistantIdField(key); });
|
|
1540
|
+
}
|
|
1541
|
+
var priorityFields = (options === null || options === void 0 ? void 0 : options.priorityFields) || AI_ASSISTANT_DISPLAY_PRIORITY_FIELDS;
|
|
1542
|
+
var priorityMap = new Map(priorityFields.map(function (field, index) { return [field.toLowerCase(), index]; }));
|
|
1543
|
+
columns.sort(function (a, b) {
|
|
1544
|
+
var _a, _b, _c, _d;
|
|
1545
|
+
var aPriority = (_a = priorityMap.get(normalizeColumnPriorityKey(a))) !== null && _a !== void 0 ? _a : 999;
|
|
1546
|
+
var bPriority = (_b = priorityMap.get(normalizeColumnPriorityKey(b))) !== null && _b !== void 0 ? _b : 999;
|
|
1547
|
+
if (aPriority !== bPriority) {
|
|
1548
|
+
return aPriority - bPriority;
|
|
1549
|
+
}
|
|
1550
|
+
var aCount = ((_c = stats.get(a)) === null || _c === void 0 ? void 0 : _c.nonEmpty) || 0;
|
|
1551
|
+
var bCount = ((_d = stats.get(b)) === null || _d === void 0 ? void 0 : _d.nonEmpty) || 0;
|
|
1552
|
+
if (aCount !== bCount) {
|
|
1553
|
+
return bCount - aCount;
|
|
1554
|
+
}
|
|
1555
|
+
return a.localeCompare(b);
|
|
1556
|
+
});
|
|
1557
|
+
var maxColumns = typeof (options === null || options === void 0 ? void 0 : options.maxColumns) === 'number'
|
|
1558
|
+
? Math.max(options.maxColumns, 0)
|
|
1559
|
+
: AI_ASSISTANT_DISPLAY_MAX_COLUMNS;
|
|
1560
|
+
if (maxColumns && columns.length > maxColumns) {
|
|
1561
|
+
columns = columns.slice(0, maxColumns);
|
|
1562
|
+
}
|
|
1563
|
+
var columnLabels = columns.map(function (column) { return formatDisplayColumnName(column) || column; });
|
|
1564
|
+
var maxRows = typeof (options === null || options === void 0 ? void 0 : options.maxRows) === 'number'
|
|
1565
|
+
? Math.max(options.maxRows, 0)
|
|
1566
|
+
: rowsRaw.length;
|
|
1567
|
+
var limitedRows = maxRows ? rowsRaw.slice(0, maxRows) : [];
|
|
1568
|
+
var rows = limitedRows.map(function (row) {
|
|
1569
|
+
var next = {};
|
|
1570
|
+
columns.forEach(function (column, index) {
|
|
1571
|
+
var label = columnLabels[index] || column;
|
|
1572
|
+
next[label] = serializeMongoValue(row[column]);
|
|
1573
|
+
});
|
|
1574
|
+
return next;
|
|
1575
|
+
});
|
|
1576
|
+
return {
|
|
1577
|
+
columns: columnLabels,
|
|
1578
|
+
rows: rows,
|
|
1579
|
+
rowCount: rowsRaw.length,
|
|
1580
|
+
truncated: rowsRaw.length > maxRows || columns.length > maxColumns,
|
|
1581
|
+
includeIds: (options === null || options === void 0 ? void 0 : options.includeIds) === true
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
function trimDisplayTable(display, options) {
|
|
1585
|
+
if (!display || !Array.isArray(display.columns)) {
|
|
1586
|
+
return display;
|
|
1587
|
+
}
|
|
1588
|
+
var rowsSource = Array.isArray(display.rows) ? display.rows : [];
|
|
1589
|
+
var maxColumns = typeof (options === null || options === void 0 ? void 0 : options.maxColumns) === 'number'
|
|
1590
|
+
? Math.max(options.maxColumns, 0)
|
|
1591
|
+
: display.columns.length;
|
|
1592
|
+
var maxRows = typeof (options === null || options === void 0 ? void 0 : options.maxRows) === 'number'
|
|
1593
|
+
? Math.max(options.maxRows, 0)
|
|
1594
|
+
: rowsSource.length;
|
|
1595
|
+
var columns = maxColumns ? display.columns.slice(0, maxColumns) : [];
|
|
1596
|
+
var rows = maxRows ? rowsSource.slice(0, maxRows).map(function (row) {
|
|
1597
|
+
var next = {};
|
|
1598
|
+
columns.forEach(function (column) {
|
|
1599
|
+
next[column] = row === null || row === void 0 ? void 0 : row[column];
|
|
1600
|
+
});
|
|
1601
|
+
return next;
|
|
1602
|
+
}) : [];
|
|
1603
|
+
return __assign(__assign({}, display), { columns: columns, rows: rows, truncated: display.truncated || display.columns.length > maxColumns || rowsSource.length > maxRows });
|
|
1604
|
+
}
|
|
1605
|
+
function formatDisplayTableMarkdown(display) {
|
|
1606
|
+
if (!display || !Array.isArray(display.columns) || !display.columns.length) {
|
|
1607
|
+
return '';
|
|
1608
|
+
}
|
|
1609
|
+
var header = "| ".concat(display.columns.join(' | '), " |");
|
|
1610
|
+
var separator = "| ".concat(display.columns.map(function () { return '---'; }).join(' | '), " |");
|
|
1611
|
+
var rows = (display.rows || []).map(function (row) {
|
|
1612
|
+
var cells = display.columns.map(function (column) { return escapeMarkdownCell(row === null || row === void 0 ? void 0 : row[column]); });
|
|
1613
|
+
return "| ".concat(cells.join(' | '), " |");
|
|
1614
|
+
});
|
|
1615
|
+
return __spreadArray([header, separator], __read(rows), false).join('\n').trim();
|
|
1616
|
+
}
|
|
1617
|
+
function escapeMarkdownCell(value) {
|
|
1618
|
+
var raw = value === null || value === undefined ? '' : String(value);
|
|
1619
|
+
return raw.replace(/\|/g, '\\|').replace(/\r?\n/g, ' ').trim();
|
|
1620
|
+
}
|
|
1621
|
+
function isEmptyDisplayValue(value) {
|
|
1622
|
+
if (value === null || value === undefined) {
|
|
1623
|
+
return true;
|
|
1624
|
+
}
|
|
1625
|
+
if (typeof value === 'string') {
|
|
1626
|
+
return !value.trim();
|
|
1627
|
+
}
|
|
1628
|
+
if (Array.isArray(value)) {
|
|
1629
|
+
return value.length === 0;
|
|
1630
|
+
}
|
|
1631
|
+
return false;
|
|
1632
|
+
}
|
|
1633
|
+
function isDisplayObjectLike(value) {
|
|
1634
|
+
if (value === null || value === undefined) {
|
|
1635
|
+
return false;
|
|
1636
|
+
}
|
|
1637
|
+
if (value instanceof Date) {
|
|
1638
|
+
return false;
|
|
1639
|
+
}
|
|
1640
|
+
if (isMongoObjectId(value)) {
|
|
1641
|
+
return false;
|
|
1642
|
+
}
|
|
1643
|
+
return typeof value === 'object';
|
|
1644
|
+
}
|
|
1074
1645
|
function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
1075
1646
|
return __awaiter(this, void 0, void 0, function () {
|
|
1076
1647
|
var idUser, user, isSuperAdmin, normalizedPermission, normalizedCollection;
|
|
@@ -1131,7 +1702,7 @@ function resolveAssistantDatabaseName(database, mongoConfig) {
|
|
|
1131
1702
|
}
|
|
1132
1703
|
function normalizeAssistantFindOptions(options) {
|
|
1133
1704
|
var normalized = options || {};
|
|
1134
|
-
var projection =
|
|
1705
|
+
var projection = sanitizeAssistantProjection(normalized.projection);
|
|
1135
1706
|
var sort = normalized.sort && Object.keys(normalized.sort).length ? normalized.sort : undefined;
|
|
1136
1707
|
var limit = typeof normalized.limit === 'number'
|
|
1137
1708
|
? Math.min(Math.max(normalized.limit, 0), AI_ASSISTANT_MONGO_MAX_LIMIT)
|
|
@@ -1147,6 +1718,33 @@ function normalizeAssistantFindOptions(options) {
|
|
|
1147
1718
|
includeTotal: normalized.includeTotal === true
|
|
1148
1719
|
};
|
|
1149
1720
|
}
|
|
1721
|
+
function sanitizeAssistantProjection(projection) {
|
|
1722
|
+
if (!projection || typeof projection !== 'object') {
|
|
1723
|
+
return undefined;
|
|
1724
|
+
}
|
|
1725
|
+
var keys = Object.keys(projection);
|
|
1726
|
+
if (!keys.length) {
|
|
1727
|
+
return undefined;
|
|
1728
|
+
}
|
|
1729
|
+
var hasInclude = false;
|
|
1730
|
+
var hasExclude = false;
|
|
1731
|
+
keys.forEach(function (key) {
|
|
1732
|
+
var value = projection[key];
|
|
1733
|
+
if (value === 0 || value === false) {
|
|
1734
|
+
hasExclude = true;
|
|
1735
|
+
}
|
|
1736
|
+
else if (value === 1 || value === true) {
|
|
1737
|
+
hasInclude = true;
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
if (hasInclude && !hasExclude) {
|
|
1741
|
+
var onlyIds = keys.every(function (key) { return isAssistantIdField(key); });
|
|
1742
|
+
if (onlyIds) {
|
|
1743
|
+
return undefined;
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
return projection;
|
|
1747
|
+
}
|
|
1150
1748
|
function normalizeAssistantAggregatePipeline(pipeline) {
|
|
1151
1749
|
if (!Array.isArray(pipeline)) {
|
|
1152
1750
|
return [];
|
|
@@ -1635,7 +2233,7 @@ var CodexWorkerBootstrapError = /** @class */ (function (_super) {
|
|
|
1635
2233
|
}(Error));
|
|
1636
2234
|
function runCodexInWorkerThread(prompt, runOptions, config) {
|
|
1637
2235
|
return __awaiter(this, void 0, void 0, function () {
|
|
1638
|
-
var codexClient, workerPath, codexClient,
|
|
2236
|
+
var codexClient, workerPath, codexClient, error_2, codexClient;
|
|
1639
2237
|
return __generator(this, function (_a) {
|
|
1640
2238
|
switch (_a.label) {
|
|
1641
2239
|
case 0:
|
|
@@ -1655,11 +2253,11 @@ function runCodexInWorkerThread(prompt, runOptions, config) {
|
|
|
1655
2253
|
return [4 /*yield*/, runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config)];
|
|
1656
2254
|
case 6: return [2 /*return*/, _a.sent()];
|
|
1657
2255
|
case 7:
|
|
1658
|
-
|
|
1659
|
-
if (!(
|
|
1660
|
-
throw
|
|
2256
|
+
error_2 = _a.sent();
|
|
2257
|
+
if (!(error_2 instanceof CodexWorkerBootstrapError)) {
|
|
2258
|
+
throw error_2;
|
|
1661
2259
|
}
|
|
1662
|
-
console.error('Codex worker bootstrap failed, falling back to in-process run.',
|
|
2260
|
+
console.error('Codex worker bootstrap failed, falling back to in-process run.', error_2);
|
|
1663
2261
|
codexClient = getAssistantCodexClient();
|
|
1664
2262
|
return [4 /*yield*/, codexClient.run(prompt, runOptions)];
|
|
1665
2263
|
case 8: return [2 /*return*/, _a.sent()];
|
|
@@ -1696,7 +2294,7 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config)
|
|
|
1696
2294
|
timeoutMs = ((sanitizedOptions === null || sanitizedOptions === void 0 ? void 0 : sanitizedOptions.timeoutMs) || resolveCodexTimeoutMs()) + 15000;
|
|
1697
2295
|
timeoutController = new AbortController();
|
|
1698
2296
|
timeoutPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1699
|
-
var
|
|
2297
|
+
var error_3;
|
|
1700
2298
|
return __generator(this, function (_a) {
|
|
1701
2299
|
switch (_a.label) {
|
|
1702
2300
|
case 0:
|
|
@@ -1706,11 +2304,11 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config)
|
|
|
1706
2304
|
_a.sent();
|
|
1707
2305
|
return [2 /*return*/, { type: 'timeout' }];
|
|
1708
2306
|
case 2:
|
|
1709
|
-
|
|
1710
|
-
if ((
|
|
2307
|
+
error_3 = _a.sent();
|
|
2308
|
+
if ((error_3 === null || error_3 === void 0 ? void 0 : error_3.name) === 'AbortError') {
|
|
1711
2309
|
return [2 /*return*/, { type: 'aborted' }];
|
|
1712
2310
|
}
|
|
1713
|
-
throw
|
|
2311
|
+
throw error_3;
|
|
1714
2312
|
case 3: return [2 /*return*/];
|
|
1715
2313
|
}
|
|
1716
2314
|
});
|
|
@@ -2068,7 +2666,7 @@ function sanitizeAssistantResponse(value) {
|
|
|
2068
2666
|
if (!raw) {
|
|
2069
2667
|
return 'I could not generate a response. Please try again.';
|
|
2070
2668
|
}
|
|
2071
|
-
var withoutBlocks = raw.replace(/```[
|
|
2669
|
+
var withoutBlocks = raw.replace(/```[\s\S]*?```/g, '').replace(/`([^`]+)`/g, '$1').trim();
|
|
2072
2670
|
var stripEstimated = function (line) { return line.replace(/\bEstimated (human )?hours:\s*.*$/i, '').trimEnd(); };
|
|
2073
2671
|
var isTentativeQueryLine = function (line) {
|
|
2074
2672
|
var normalized = line.trim().replace(/^[-*•]+\s*/, '');
|