@resolveio/server-lib 20.14.3 → 20.14.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.
- package/methods/ai-terminal.d.ts +21 -0
- package/methods/ai-terminal.js +564 -50
- package/methods/ai-terminal.js.map +1 -1
- package/methods/report-builder.js +290 -14
- package/methods/report-builder.js.map +1 -1
- package/methods.ts +6 -0
- package/package.json +1 -1
- package/util/tokenizer.js +7 -1
- package/util/tokenizer.js.map +1 -1
package/methods/ai-terminal.js
CHANGED
|
@@ -48,6 +48,7 @@ var __values = (this && this.__values) || function(o) {
|
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
50
|
exports.loadAiTerminalMethods = loadAiTerminalMethods;
|
|
51
|
+
exports.executeAiAssistantMongoRead = executeAiAssistantMongoRead;
|
|
51
52
|
var fs_1 = require("fs");
|
|
52
53
|
var os = require("os");
|
|
53
54
|
var path = require("path");
|
|
@@ -67,21 +68,79 @@ var DEFAULT_MAX_ATTACHMENT_CHARS = 12000;
|
|
|
67
68
|
var DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS = 40000;
|
|
68
69
|
var DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
|
|
69
70
|
var DEFAULT_CODEX_TIMEOUT_MS = 180000;
|
|
71
|
+
var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
|
|
72
|
+
var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
|
|
73
|
+
var AI_ASSISTANT_BLOCKED_COLLECTIONS = new Set([
|
|
74
|
+
'user-groups',
|
|
75
|
+
'logged-in-users',
|
|
76
|
+
'ai-terminal-messages',
|
|
77
|
+
'ai-terminal-conversations',
|
|
78
|
+
'openai-usage-ledger',
|
|
79
|
+
'logs',
|
|
80
|
+
'notifications',
|
|
81
|
+
'email-history'
|
|
82
|
+
]);
|
|
83
|
+
var AI_ASSISTANT_SENSITIVE_FIELDS = [
|
|
84
|
+
'password',
|
|
85
|
+
'salt',
|
|
86
|
+
'hash',
|
|
87
|
+
'secret',
|
|
88
|
+
'token',
|
|
89
|
+
'api_key',
|
|
90
|
+
'email',
|
|
91
|
+
'phonenumber',
|
|
92
|
+
'phone',
|
|
93
|
+
'ssn',
|
|
94
|
+
'address',
|
|
95
|
+
'services',
|
|
96
|
+
'roles'
|
|
97
|
+
];
|
|
70
98
|
var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
71
99
|
'You are the ResolveIO in-app AI assistant running with read-only access to the codebase.',
|
|
72
|
-
'-
|
|
73
|
-
'- Do not modify files, run destructive commands, or access databases.',
|
|
100
|
+
'- Never share code or file contents. All code is proprietary.',
|
|
101
|
+
'- Do not modify files, run destructive commands, or access databases directly.',
|
|
102
|
+
'- Read-only Mongo access is allowed only via the MONGO_READ directive (see below).',
|
|
74
103
|
'- Do not access secrets, credentials, or user data.',
|
|
75
104
|
'- Do not assist with hacking, bypassing security, or abuse.',
|
|
76
105
|
'- Prefer high-level explanations and point to routes instead of code. Only mention file paths if explicitly requested.',
|
|
77
106
|
'- 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.',
|
|
107
|
+
'- When asked "why is this happening," respond with: cause, trigger, data source(s), and expected vs actual outcome.',
|
|
108
|
+
'- For troubleshooting, ask 2-3 targeted questions first, then give a short decision tree (If X, do Y; If not, do Z).',
|
|
109
|
+
'- Provide checklists for common tasks, highlighting required fields and common pitfalls.',
|
|
110
|
+
'- If asked "where is this set," give the screen/workflow name and navigation steps to reach it.',
|
|
111
|
+
'- If asked "what changed," summarize release notes if known; if not available, say so and suggest where to check or offer a support ticket.',
|
|
112
|
+
'- Suggest 1-2 related screens or next steps when it helps.',
|
|
113
|
+
'- If access is blocked, name the permission/role needed and how to request it.',
|
|
78
114
|
'- Avoid vague labels like "Operations app"; use the specific screen/workflow name.',
|
|
79
115
|
'- Do not mention other client projects or ask which client; stay within the current project context.',
|
|
80
116
|
'- Respond with a single concise message. Do not add labels like "Customer-facing summary" or "Work ticket summary" and do not include estimated hours.',
|
|
117
|
+
'- 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.',
|
|
118
|
+
'- When giving steps, include navigation guidance like "Go to <screen>" and "Click/Select/Enter <field>" so the user can follow it exactly.',
|
|
81
119
|
'- If context scope is provided (ex: current page), prioritize that screen in your answer.',
|
|
82
120
|
'- If a request is out of scope, offer to create a support ticket with a short summary.',
|
|
121
|
+
'- If the user explicitly asks to create/open/file a support ticket, end your response with a single line exactly in this format:',
|
|
122
|
+
'- SUPPORT_TICKET_CREATE: <one-line summary>',
|
|
123
|
+
'- Only include that line when the user clearly wants a ticket created. Do not claim a ticket is created unless you include that line.',
|
|
124
|
+
'- If you need database data to answer, end your response with a single line exactly in this format:',
|
|
125
|
+
'- MONGO_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
|
|
126
|
+
'- For invoice data, set permissionView to an invoice route (ex: /invoice/list or /report/invoice).',
|
|
127
|
+
'- Keep queries minimal, read-only, and avoid user/credential data unless the user is a super admin.',
|
|
128
|
+
'- Assume you are not a super admin unless explicitly told otherwise.',
|
|
129
|
+
'- Only request data when the user has permission for that module; invoice data requires invoice view access.',
|
|
130
|
+
'- If the user lacks permission, answer without data and explain how to view it in the app or request access.',
|
|
131
|
+
'- Use MONGO_READ only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
|
|
132
|
+
'- When referencing data, summarize it in bullets and avoid raw JSON or dumps.',
|
|
83
133
|
'- Keep responses concise and use low reasoning effort.'
|
|
84
134
|
].join('\n');
|
|
135
|
+
var AI_FORM_PATCH_SYSTEM_PROMPT = [
|
|
136
|
+
'You are the ResolveIO form patch assistant.',
|
|
137
|
+
'- Your job is to map the user request to the provided form fields.',
|
|
138
|
+
'- Only use the allowed fields and their types.',
|
|
139
|
+
'- Return ONLY valid JSON and nothing else.',
|
|
140
|
+
'- If you cannot map the request, return an empty patch with a short note.',
|
|
141
|
+
'- Use ISO 8601 for dates and true/false for booleans.',
|
|
142
|
+
'- Use medium reasoning effort.'
|
|
143
|
+
].join('\n');
|
|
85
144
|
var assistantCodexClient = null;
|
|
86
145
|
function loadAiTerminalMethods(methodManager) {
|
|
87
146
|
methodManager.methods({
|
|
@@ -267,6 +326,24 @@ function loadAiTerminalMethods(methodManager) {
|
|
|
267
326
|
});
|
|
268
327
|
}
|
|
269
328
|
},
|
|
329
|
+
aiFormPatch: {
|
|
330
|
+
check: new simpl_schema_1.default({
|
|
331
|
+
payload: {
|
|
332
|
+
type: Object,
|
|
333
|
+
blackbox: true
|
|
334
|
+
}
|
|
335
|
+
}),
|
|
336
|
+
function: function (payload) {
|
|
337
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
338
|
+
return __generator(this, function (_a) {
|
|
339
|
+
switch (_a.label) {
|
|
340
|
+
case 0: return [4 /*yield*/, executeAiFormPatch(payload, this)];
|
|
341
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
},
|
|
270
347
|
aiCoderTerminalUploadFile: {
|
|
271
348
|
check: new simpl_schema_1.default({
|
|
272
349
|
id_conversation: {
|
|
@@ -315,6 +392,24 @@ function loadAiTerminalMethods(methodManager) {
|
|
|
315
392
|
});
|
|
316
393
|
}
|
|
317
394
|
},
|
|
395
|
+
aiAssistantMongoRead: {
|
|
396
|
+
check: new simpl_schema_1.default({
|
|
397
|
+
payload: {
|
|
398
|
+
type: Object,
|
|
399
|
+
blackbox: true
|
|
400
|
+
}
|
|
401
|
+
}),
|
|
402
|
+
function: function (payload) {
|
|
403
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
404
|
+
return __generator(this, function (_a) {
|
|
405
|
+
switch (_a.label) {
|
|
406
|
+
case 0: return [4 /*yield*/, executeAiAssistantMongoRead(payload, this)];
|
|
407
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
},
|
|
318
413
|
aiCoderTerminalDeployTest: {
|
|
319
414
|
check: new simpl_schema_1.default({
|
|
320
415
|
id_conversation: {
|
|
@@ -483,11 +578,79 @@ function executeAiTerminalRun(payload, context) {
|
|
|
483
578
|
});
|
|
484
579
|
});
|
|
485
580
|
}
|
|
486
|
-
function
|
|
581
|
+
function executeAiFormPatch(payload, context) {
|
|
487
582
|
return __awaiter(this, void 0, void 0, function () {
|
|
488
|
-
var input, message,
|
|
583
|
+
var input, message, allowedFields, guardrail, systemPrompt, userPrompt, messages, openaiSettings, client, response, usage, idClient, parsed;
|
|
584
|
+
var _a;
|
|
489
585
|
return __generator(this, function (_b) {
|
|
490
586
|
switch (_b.label) {
|
|
587
|
+
case 0:
|
|
588
|
+
input = payload || {};
|
|
589
|
+
message = normalizeOptionalString(input.message);
|
|
590
|
+
if (!message) {
|
|
591
|
+
throw new Error('Message is required.');
|
|
592
|
+
}
|
|
593
|
+
if (!(context === null || context === void 0 ? void 0 : context.id_user)) {
|
|
594
|
+
throw new Error('Unauthorized.');
|
|
595
|
+
}
|
|
596
|
+
allowedFields = normalizeAiFormFields(input.allowed_fields || input.fields);
|
|
597
|
+
if (!allowedFields.length) {
|
|
598
|
+
throw new Error('Allowed fields are required.');
|
|
599
|
+
}
|
|
600
|
+
guardrail = evaluateGuardrails(message);
|
|
601
|
+
if (guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked) {
|
|
602
|
+
return [2 /*return*/, { error: guardrail.response, blocked: true }];
|
|
603
|
+
}
|
|
604
|
+
systemPrompt = buildAiFormSystemPrompt();
|
|
605
|
+
userPrompt = buildAiFormUserPrompt(message, allowedFields, input.patch_format, input.route);
|
|
606
|
+
messages = [
|
|
607
|
+
{ role: 'system', content: systemPrompt },
|
|
608
|
+
{ role: 'user', content: userPrompt }
|
|
609
|
+
];
|
|
610
|
+
openaiSettings = resolveOpenAISettings(input.config || {});
|
|
611
|
+
client = new openai_client_1.OpenAIClient(openaiSettings);
|
|
612
|
+
return [4 /*yield*/, client.chat(messages, { timeoutMs: 60000, responseFormat: 'json_object' })];
|
|
613
|
+
case 1:
|
|
614
|
+
response = _b.sent();
|
|
615
|
+
usage = response.usage || estimateUsage(messages, response.content, response.model || openaiSettings.model);
|
|
616
|
+
idClient = normalizeOptionalString(input.id_client);
|
|
617
|
+
if (!idClient) return [3 /*break*/, 3];
|
|
618
|
+
return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
|
|
619
|
+
id_client: idClient,
|
|
620
|
+
model: response.model || openaiSettings.model || 'unknown',
|
|
621
|
+
input_tokens: usage.inputTokens,
|
|
622
|
+
output_tokens: usage.outputTokens,
|
|
623
|
+
total_tokens: usage.totalTokens,
|
|
624
|
+
category: 'ai-form'
|
|
625
|
+
})];
|
|
626
|
+
case 2:
|
|
627
|
+
_b.sent();
|
|
628
|
+
_b.label = 3;
|
|
629
|
+
case 3:
|
|
630
|
+
parsed = parseJsonObject(response.content);
|
|
631
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
632
|
+
throw new Error('AI form patch response was not valid JSON.');
|
|
633
|
+
}
|
|
634
|
+
return [2 /*return*/, {
|
|
635
|
+
patch: (_a = parsed.patch) !== null && _a !== void 0 ? _a : parsed,
|
|
636
|
+
notes: normalizeOptionalString(parsed.notes) || undefined,
|
|
637
|
+
usage: {
|
|
638
|
+
model: response.model || openaiSettings.model,
|
|
639
|
+
input_tokens: usage.inputTokens,
|
|
640
|
+
output_tokens: usage.outputTokens,
|
|
641
|
+
total_tokens: usage.totalTokens
|
|
642
|
+
}
|
|
643
|
+
}];
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function executeAiAssistantCodexRun(payload, context) {
|
|
649
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
650
|
+
var input, message, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, prompt, workspaceRoot, codexClient, runOptions, responseText, assistantContent, userDoc, assistantDoc, insertResult;
|
|
651
|
+
var _b;
|
|
652
|
+
return __generator(this, function (_c) {
|
|
653
|
+
switch (_c.label) {
|
|
491
654
|
case 0:
|
|
492
655
|
input = payload || {};
|
|
493
656
|
message = normalizeOptionalString(input.message);
|
|
@@ -501,7 +664,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
501
664
|
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
|
|
502
665
|
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
503
666
|
case 1:
|
|
504
|
-
conversation_2 =
|
|
667
|
+
conversation_2 = _c.sent();
|
|
505
668
|
now_2 = new Date();
|
|
506
669
|
userMsg = {
|
|
507
670
|
id_conversation: conversation_2._id,
|
|
@@ -523,36 +686,41 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
523
686
|
};
|
|
524
687
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userMsg)];
|
|
525
688
|
case 2:
|
|
526
|
-
|
|
689
|
+
_c.sent();
|
|
527
690
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantMsg)];
|
|
528
691
|
case 3:
|
|
529
|
-
|
|
692
|
+
_c.sent();
|
|
530
693
|
return [4 /*yield*/, touchConversation(conversation_2._id, now_2)];
|
|
531
694
|
case 4:
|
|
532
|
-
|
|
695
|
+
_c.sent();
|
|
533
696
|
return [2 /*return*/, {
|
|
534
697
|
conversation: conversation_2,
|
|
535
698
|
message: assistantMsg,
|
|
536
699
|
guardrails: { blocked: true, reason: guardrail.reason }
|
|
537
700
|
}];
|
|
538
|
-
case 5: return [4 /*yield*/,
|
|
701
|
+
case 5: return [4 /*yield*/, user_collection_1.Users.findById(context === null || context === void 0 ? void 0 : context.id_user)];
|
|
539
702
|
case 6:
|
|
540
|
-
|
|
703
|
+
user = _c.sent();
|
|
704
|
+
isSuperAdmin = !!((_b = user === null || user === void 0 ? void 0 : user.roles) === null || _b === void 0 ? void 0 : _b.super_admin);
|
|
705
|
+
hasInvoiceAccess = userHasInvoiceAccess(user);
|
|
706
|
+
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
707
|
+
case 7:
|
|
708
|
+
conversation = _c.sent();
|
|
541
709
|
now = new Date();
|
|
542
710
|
attachments = Array.isArray(input.attachments) ? input.attachments : [];
|
|
543
711
|
return [4 /*yield*/, readAttachmentContents(attachments)];
|
|
544
|
-
case
|
|
545
|
-
attachmentData =
|
|
712
|
+
case 8:
|
|
713
|
+
attachmentData = _c.sent();
|
|
546
714
|
historyLimit = normalizeHistoryLimit(input.max_history);
|
|
547
|
-
if (!(historyLimit > 0)) return [3 /*break*/,
|
|
715
|
+
if (!(historyLimit > 0)) return [3 /*break*/, 10];
|
|
548
716
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find({ id_conversation: conversation._id, role: { $in: ['user', 'assistant'] } }, { sort: { createdAt: 1 }, limit: historyLimit * 2 })];
|
|
549
|
-
case 8:
|
|
550
|
-
_a = _b.sent();
|
|
551
|
-
return [3 /*break*/, 10];
|
|
552
717
|
case 9:
|
|
553
|
-
_a =
|
|
554
|
-
|
|
718
|
+
_a = _c.sent();
|
|
719
|
+
return [3 /*break*/, 11];
|
|
555
720
|
case 10:
|
|
721
|
+
_a = [];
|
|
722
|
+
_c.label = 11;
|
|
723
|
+
case 11:
|
|
556
724
|
history = _a;
|
|
557
725
|
historyLines = [];
|
|
558
726
|
history.forEach(function (entry) {
|
|
@@ -562,10 +730,10 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
562
730
|
historyLines.push("".concat(role, ": ").concat(content));
|
|
563
731
|
}
|
|
564
732
|
});
|
|
565
|
-
prompt = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), buildAssistantContext(input));
|
|
733
|
+
prompt = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), buildAssistantContext(input, { isSuperAdmin: isSuperAdmin, hasInvoiceAccess: hasInvoiceAccess }));
|
|
566
734
|
return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
|
|
567
|
-
case
|
|
568
|
-
workspaceRoot =
|
|
735
|
+
case 12:
|
|
736
|
+
workspaceRoot = _c.sent();
|
|
569
737
|
codexClient = getAssistantCodexClient();
|
|
570
738
|
runOptions = {
|
|
571
739
|
timeoutMs: resolveCodexTimeoutMs(),
|
|
@@ -581,8 +749,8 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
581
749
|
}
|
|
582
750
|
};
|
|
583
751
|
return [4 /*yield*/, codexClient.run(prompt, runOptions)];
|
|
584
|
-
case
|
|
585
|
-
responseText =
|
|
752
|
+
case 13:
|
|
753
|
+
responseText = _c.sent();
|
|
586
754
|
assistantContent = sanitizeAssistantResponse(responseText);
|
|
587
755
|
userDoc = {
|
|
588
756
|
id_conversation: conversation._id,
|
|
@@ -603,20 +771,20 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
603
771
|
updatedAt: now
|
|
604
772
|
};
|
|
605
773
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
|
|
606
|
-
case 13:
|
|
607
|
-
_b.sent();
|
|
608
|
-
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
|
|
609
774
|
case 14:
|
|
610
|
-
|
|
611
|
-
return [4 /*yield*/,
|
|
775
|
+
_c.sent();
|
|
776
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
|
|
612
777
|
case 15:
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
|
|
778
|
+
insertResult = _c.sent();
|
|
779
|
+
return [4 /*yield*/, touchConversation(conversation._id, now, insertResult._id)];
|
|
616
780
|
case 16:
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
781
|
+
_c.sent();
|
|
782
|
+
if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 18];
|
|
783
|
+
return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
|
|
784
|
+
case 17:
|
|
785
|
+
_c.sent();
|
|
786
|
+
_c.label = 18;
|
|
787
|
+
case 18: return [2 /*return*/, {
|
|
620
788
|
conversation: conversation,
|
|
621
789
|
message: assistantDoc
|
|
622
790
|
}];
|
|
@@ -624,6 +792,243 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
624
792
|
});
|
|
625
793
|
});
|
|
626
794
|
}
|
|
795
|
+
function executeAiAssistantMongoRead(payload, context) {
|
|
796
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
797
|
+
var input, collection, _a, user, isSuperAdmin, dbName, db, baseQuery, userId, scopedQuery, normalized, documents, total, sanitizedDocuments;
|
|
798
|
+
return __generator(this, function (_b) {
|
|
799
|
+
switch (_b.label) {
|
|
800
|
+
case 0:
|
|
801
|
+
input = payload || {};
|
|
802
|
+
collection = normalizeOptionalString(input.collection);
|
|
803
|
+
if (!collection) {
|
|
804
|
+
throw new Error('AI assistant mongo read: Collection is required.');
|
|
805
|
+
}
|
|
806
|
+
return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
|
|
807
|
+
case 1:
|
|
808
|
+
_a = _b.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
|
|
809
|
+
if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
|
|
810
|
+
throw new Error('AI assistant mongo read: Access denied.');
|
|
811
|
+
}
|
|
812
|
+
dbName = resolveAssistantDatabaseName(input.database, input.mongo);
|
|
813
|
+
db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
|
|
814
|
+
baseQuery = normalizeMongoQuery(input.query);
|
|
815
|
+
if (!isSuperAdmin && (collection === 'users' || collection === 'user-versions')) {
|
|
816
|
+
userId = normalizeOptionalString(user === null || user === void 0 ? void 0 : user._id);
|
|
817
|
+
if (!userId) {
|
|
818
|
+
throw new Error('AI assistant mongo read: Access denied.');
|
|
819
|
+
}
|
|
820
|
+
baseQuery = {
|
|
821
|
+
$and: [baseQuery, { _id: userId }]
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
scopedQuery = applyClientScopeFilter(baseQuery, input.id_client, isSuperAdmin);
|
|
825
|
+
normalized = normalizeAssistantFindOptions(input.options);
|
|
826
|
+
return [4 /*yield*/, db.collection(collection).find(scopedQuery, normalized.findOptions).toArray()];
|
|
827
|
+
case 2:
|
|
828
|
+
documents = _b.sent();
|
|
829
|
+
total = null;
|
|
830
|
+
if (!normalized.includeTotal) return [3 /*break*/, 4];
|
|
831
|
+
return [4 /*yield*/, db.collection(collection).countDocuments(scopedQuery)];
|
|
832
|
+
case 3:
|
|
833
|
+
total = _b.sent();
|
|
834
|
+
_b.label = 4;
|
|
835
|
+
case 4:
|
|
836
|
+
sanitizedDocuments = isSuperAdmin
|
|
837
|
+
? documents
|
|
838
|
+
: documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
|
|
839
|
+
return [2 /*return*/, {
|
|
840
|
+
documents: sanitizedDocuments,
|
|
841
|
+
total: total
|
|
842
|
+
}];
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
848
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
849
|
+
var idUser, user, isSuperAdmin, normalizedPermission, normalizedCollection;
|
|
850
|
+
var _a;
|
|
851
|
+
return __generator(this, function (_b) {
|
|
852
|
+
switch (_b.label) {
|
|
853
|
+
case 0:
|
|
854
|
+
idUser = context === null || context === void 0 ? void 0 : context.id_user;
|
|
855
|
+
if (!idUser) {
|
|
856
|
+
throw new Error('AI assistant mongo read: Unauthorized.');
|
|
857
|
+
}
|
|
858
|
+
return [4 /*yield*/, user_collection_1.Users.findById(idUser)];
|
|
859
|
+
case 1:
|
|
860
|
+
user = _b.sent();
|
|
861
|
+
if (!user) {
|
|
862
|
+
throw new Error('AI assistant mongo read: Unauthorized.');
|
|
863
|
+
}
|
|
864
|
+
isSuperAdmin = !!((_a = user === null || user === void 0 ? void 0 : user.roles) === null || _a === void 0 ? void 0 : _a.super_admin);
|
|
865
|
+
normalizedPermission = normalizeOptionalString(permissionView);
|
|
866
|
+
if (!isSuperAdmin) {
|
|
867
|
+
if (!normalizedPermission) {
|
|
868
|
+
throw new Error('AI assistant mongo read: Permission scope required.');
|
|
869
|
+
}
|
|
870
|
+
if (!userHasViewPermission(user, normalizedPermission)) {
|
|
871
|
+
throw new Error('AI assistant mongo read: Access denied.');
|
|
872
|
+
}
|
|
873
|
+
normalizedCollection = normalizeOptionalString(collection);
|
|
874
|
+
if (normalizedCollection && requiresInvoicePermission(normalizedCollection) && !userHasInvoiceAccess(user)) {
|
|
875
|
+
throw new Error('AI assistant mongo read: Access denied.');
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else if (normalizedPermission && !userHasViewPermission(user, normalizedPermission)) {
|
|
879
|
+
throw new Error('AI assistant mongo read: Access denied.');
|
|
880
|
+
}
|
|
881
|
+
return [2 /*return*/, { user: user, isSuperAdmin: isSuperAdmin }];
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
function resolveAssistantDatabaseName(database, mongoConfig) {
|
|
887
|
+
var _a, _b;
|
|
888
|
+
var defaultDb = normalizeOptionalString(mongoConfig === null || mongoConfig === void 0 ? void 0 : mongoConfig.database) || ((_a = resolveio_server_app_1.ResolveIOServer.getServerConfig()) === null || _a === void 0 ? void 0 : _a.DATABASE) || '';
|
|
889
|
+
var dbName = normalizeOptionalString(database) || defaultDb;
|
|
890
|
+
if (!dbName) {
|
|
891
|
+
throw new Error('AI assistant mongo read: Database is required.');
|
|
892
|
+
}
|
|
893
|
+
var allowedFromConfig = Array.isArray(mongoConfig === null || mongoConfig === void 0 ? void 0 : mongoConfig.databases)
|
|
894
|
+
? mongoConfig === null || mongoConfig === void 0 ? void 0 : mongoConfig.databases.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
|
|
895
|
+
: [];
|
|
896
|
+
if (allowedFromConfig.length && !allowedFromConfig.includes(dbName)) {
|
|
897
|
+
throw new Error('AI assistant mongo read: Database access denied.');
|
|
898
|
+
}
|
|
899
|
+
var allowedDatabases = ((_b = resolveio_server_app_1.ResolveIOServer.getMongoManager()) === null || _b === void 0 ? void 0 : _b.getWatchedDatabases()) || [];
|
|
900
|
+
if (allowedDatabases.length && !allowedDatabases.includes(dbName)) {
|
|
901
|
+
throw new Error('AI assistant mongo read: Database access denied.');
|
|
902
|
+
}
|
|
903
|
+
return dbName;
|
|
904
|
+
}
|
|
905
|
+
function normalizeAssistantFindOptions(options) {
|
|
906
|
+
var normalized = options || {};
|
|
907
|
+
var projection = normalized.projection && Object.keys(normalized.projection).length ? normalized.projection : undefined;
|
|
908
|
+
var sort = normalized.sort && Object.keys(normalized.sort).length ? normalized.sort : undefined;
|
|
909
|
+
var limit = typeof normalized.limit === 'number'
|
|
910
|
+
? Math.min(Math.max(normalized.limit, 0), AI_ASSISTANT_MONGO_MAX_LIMIT)
|
|
911
|
+
: AI_ASSISTANT_MONGO_DEFAULT_LIMIT;
|
|
912
|
+
var skip = typeof normalized.skip === 'number' ? Math.max(normalized.skip, 0) : 0;
|
|
913
|
+
return {
|
|
914
|
+
findOptions: {
|
|
915
|
+
projection: projection,
|
|
916
|
+
sort: sort,
|
|
917
|
+
limit: limit,
|
|
918
|
+
skip: skip
|
|
919
|
+
},
|
|
920
|
+
includeTotal: normalized.includeTotal === true
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
function normalizeMongoQuery(query) {
|
|
924
|
+
var normalized = query && typeof query === 'object' ? query : {};
|
|
925
|
+
if (containsForbiddenMongoOperators(normalized)) {
|
|
926
|
+
throw new Error('AI assistant mongo read: Query contains restricted operators.');
|
|
927
|
+
}
|
|
928
|
+
return normalized;
|
|
929
|
+
}
|
|
930
|
+
function containsForbiddenMongoOperators(value) {
|
|
931
|
+
var e_1, _a;
|
|
932
|
+
if (!value || typeof value !== 'object') {
|
|
933
|
+
return false;
|
|
934
|
+
}
|
|
935
|
+
if (Array.isArray(value)) {
|
|
936
|
+
return value.some(function (entry) { return containsForbiddenMongoOperators(entry); });
|
|
937
|
+
}
|
|
938
|
+
try {
|
|
939
|
+
for (var _b = __values(Object.keys(value)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
940
|
+
var key = _c.value;
|
|
941
|
+
var normalized = key.toLowerCase();
|
|
942
|
+
if (normalized === '$where' || normalized === '$function' || normalized === '$accumulator') {
|
|
943
|
+
return true;
|
|
944
|
+
}
|
|
945
|
+
if (containsForbiddenMongoOperators(value[key])) {
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
951
|
+
finally {
|
|
952
|
+
try {
|
|
953
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
954
|
+
}
|
|
955
|
+
finally { if (e_1) throw e_1.error; }
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
function applyClientScopeFilter(query, idClient, isSuperAdmin) {
|
|
960
|
+
if (isSuperAdmin === void 0) { isSuperAdmin = false; }
|
|
961
|
+
if (isSuperAdmin) {
|
|
962
|
+
return query;
|
|
963
|
+
}
|
|
964
|
+
var normalizedClient = normalizeOptionalString(idClient);
|
|
965
|
+
if (!normalizedClient) {
|
|
966
|
+
return query;
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
$and: [query, { id_client: normalizedClient }]
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
function userHasViewPermission(user, view) {
|
|
973
|
+
var _a, _b, _c;
|
|
974
|
+
if (!user || !view) {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
if ((_a = user.roles) === null || _a === void 0 ? void 0 : _a.super_admin) {
|
|
978
|
+
return true;
|
|
979
|
+
}
|
|
980
|
+
var groups = Array.isArray((_b = user.roles) === null || _b === void 0 ? void 0 : _b.groups) ? user.roles.groups : [];
|
|
981
|
+
var miscs = Array.isArray((_c = user.roles) === null || _c === void 0 ? void 0 : _c.miscs) ? user.roles.miscs : [];
|
|
982
|
+
if (groups.some(function (group) { return Array.isArray(group.views) && group.views.some(function (v) { return v.startsWith(view); }); })) {
|
|
983
|
+
return true;
|
|
984
|
+
}
|
|
985
|
+
if (miscs.some(function (v) { return v.startsWith(view); })) {
|
|
986
|
+
return true;
|
|
987
|
+
}
|
|
988
|
+
if (groups.some(function (group) { return group.name === view; })) {
|
|
989
|
+
return true;
|
|
990
|
+
}
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
function userHasAnyViewPermission(user, views) {
|
|
994
|
+
if (!user || !Array.isArray(views)) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
return views.some(function (view) { return view && userHasViewPermission(user, view); });
|
|
998
|
+
}
|
|
999
|
+
function userHasInvoiceAccess(user) {
|
|
1000
|
+
return userHasAnyViewPermission(user, ['/invoice', '/report/invoice']);
|
|
1001
|
+
}
|
|
1002
|
+
function requiresInvoicePermission(collection) {
|
|
1003
|
+
var normalized = normalizeOptionalString(collection).toLowerCase();
|
|
1004
|
+
if (!normalized) {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
return normalized.includes('invoice');
|
|
1008
|
+
}
|
|
1009
|
+
function redactSensitiveFields(value) {
|
|
1010
|
+
if (Array.isArray(value)) {
|
|
1011
|
+
return value.map(function (entry) { return redactSensitiveFields(entry); });
|
|
1012
|
+
}
|
|
1013
|
+
if (!value || typeof value !== 'object') {
|
|
1014
|
+
return value;
|
|
1015
|
+
}
|
|
1016
|
+
var result = {};
|
|
1017
|
+
Object.keys(value).forEach(function (key) {
|
|
1018
|
+
if (shouldRedactField(key)) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
result[key] = redactSensitiveFields(value[key]);
|
|
1022
|
+
});
|
|
1023
|
+
return result;
|
|
1024
|
+
}
|
|
1025
|
+
function shouldRedactField(key) {
|
|
1026
|
+
var normalized = String(key || '').trim().toLowerCase();
|
|
1027
|
+
if (!normalized) {
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
return AI_ASSISTANT_SENSITIVE_FIELDS.some(function (field) { return normalized === field || normalized.includes(field); });
|
|
1031
|
+
}
|
|
627
1032
|
function resolveCodexTimeoutMs() {
|
|
628
1033
|
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
629
1034
|
var raw = normalizeOptionalNumber(config['AI_ASSISTANT_CODEX_TIMEOUT_MS'] || process.env.AI_ASSISTANT_CODEX_TIMEOUT_MS);
|
|
@@ -702,13 +1107,19 @@ function buildAssistantCodexPrompt(message, attachmentText, historyText, context
|
|
|
702
1107
|
var historyBlock = trimmedHistory ? "\n\nConversation so far:\n".concat(trimmedHistory) : '';
|
|
703
1108
|
return "System:\n".concat(AI_ASSISTANT_SYSTEM_PROMPT).concat(contextBlock).concat(historyBlock, "\n\nUser:\n").concat(message).concat(attachmentText || '').trim();
|
|
704
1109
|
}
|
|
705
|
-
function buildAssistantContext(input) {
|
|
706
|
-
var _a, _b;
|
|
1110
|
+
function buildAssistantContext(input, userContext) {
|
|
1111
|
+
var _a, _b, _c, _d, _e, _f;
|
|
707
1112
|
var lines = [];
|
|
708
1113
|
var idApp = normalizeOptionalString(input === null || input === void 0 ? void 0 : input.id_app);
|
|
709
1114
|
if (idApp) {
|
|
710
1115
|
lines.push("Current app id: ".concat(idApp));
|
|
711
1116
|
}
|
|
1117
|
+
if (typeof (userContext === null || userContext === void 0 ? void 0 : userContext.isSuperAdmin) === 'boolean') {
|
|
1118
|
+
lines.push("User is super admin: ".concat(userContext.isSuperAdmin ? 'yes' : 'no'));
|
|
1119
|
+
}
|
|
1120
|
+
if (typeof (userContext === null || userContext === void 0 ? void 0 : userContext.hasInvoiceAccess) === 'boolean') {
|
|
1121
|
+
lines.push("User has invoice access: ".concat(userContext.hasInvoiceAccess ? 'yes' : 'no'));
|
|
1122
|
+
}
|
|
712
1123
|
var contextMode = normalizeOptionalString((_a = input === null || input === void 0 ? void 0 : input.context) === null || _a === void 0 ? void 0 : _a.mode);
|
|
713
1124
|
var contextRoute = normalizeOptionalString((_b = input === null || input === void 0 ? void 0 : input.context) === null || _b === void 0 ? void 0 : _b.route);
|
|
714
1125
|
if (contextMode) {
|
|
@@ -717,6 +1128,21 @@ function buildAssistantContext(input) {
|
|
|
717
1128
|
if (contextRoute) {
|
|
718
1129
|
lines.push("Current page route: ".concat(contextRoute));
|
|
719
1130
|
}
|
|
1131
|
+
var mongoDb = normalizeOptionalString((_c = input === null || input === void 0 ? void 0 : input.mongo) === null || _c === void 0 ? void 0 : _c.database);
|
|
1132
|
+
var mongoDbs = Array.isArray((_d = input === null || input === void 0 ? void 0 : input.mongo) === null || _d === void 0 ? void 0 : _d.databases)
|
|
1133
|
+
? input.mongo.databases.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
|
|
1134
|
+
: [];
|
|
1135
|
+
var mongoAccess = normalizeOptionalString((_e = input === null || input === void 0 ? void 0 : input.mongo) === null || _e === void 0 ? void 0 : _e.access)
|
|
1136
|
+
|| (((_f = input === null || input === void 0 ? void 0 : input.mongo) === null || _f === void 0 ? void 0 : _f.readonly) === true ? 'read' : '');
|
|
1137
|
+
if (mongoDb) {
|
|
1138
|
+
lines.push("Mongo database: ".concat(mongoDb));
|
|
1139
|
+
}
|
|
1140
|
+
if (mongoDbs.length) {
|
|
1141
|
+
lines.push("Mongo databases allowed: ".concat(mongoDbs.join(', ')));
|
|
1142
|
+
}
|
|
1143
|
+
if (mongoAccess) {
|
|
1144
|
+
lines.push("Mongo access: ".concat(mongoAccess));
|
|
1145
|
+
}
|
|
720
1146
|
return lines.join('\n');
|
|
721
1147
|
}
|
|
722
1148
|
function sanitizeAssistantResponse(value) {
|
|
@@ -756,18 +1182,18 @@ function sanitizeAssistantResponse(value) {
|
|
|
756
1182
|
return cleaned;
|
|
757
1183
|
}
|
|
758
1184
|
function evaluateAssistantGuardrails(message) {
|
|
759
|
-
var
|
|
1185
|
+
var e_2, _a;
|
|
760
1186
|
var normalized = String(message || '').toLowerCase();
|
|
761
1187
|
var patterns = [
|
|
762
1188
|
{
|
|
763
1189
|
pattern: /\b(show|share|paste|provide|dump|output)\b.*\b(code|snippet|file|function|class|script|sql)\b/i,
|
|
764
1190
|
reason: 'Code sharing is restricted.',
|
|
765
|
-
response: 'I can’t share code. I can explain behavior and point you to
|
|
1191
|
+
response: 'I can’t share code or file contents. All code is proprietary. I can explain behavior and point you to screens or routes.'
|
|
766
1192
|
},
|
|
767
1193
|
{
|
|
768
1194
|
pattern: /\b(write|generate|create|implement|fix)\b.*\b(code|script|function|class|endpoint|sql)\b/i,
|
|
769
1195
|
reason: 'Code generation is restricted.',
|
|
770
|
-
response: 'I can’t generate code. I can explain how the feature works and where to look in the
|
|
1196
|
+
response: 'I can’t generate code. All code is proprietary. I can explain how the feature works and where to look in the product.'
|
|
771
1197
|
},
|
|
772
1198
|
{
|
|
773
1199
|
pattern: /\b(credentials?|passwords?|secrets?|tokens?)\b/i,
|
|
@@ -802,12 +1228,12 @@ function evaluateAssistantGuardrails(message) {
|
|
|
802
1228
|
}
|
|
803
1229
|
}
|
|
804
1230
|
}
|
|
805
|
-
catch (
|
|
1231
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
806
1232
|
finally {
|
|
807
1233
|
try {
|
|
808
1234
|
if (patterns_1_1 && !patterns_1_1.done && (_a = patterns_1.return)) _a.call(patterns_1);
|
|
809
1235
|
}
|
|
810
|
-
finally { if (
|
|
1236
|
+
finally { if (e_2) throw e_2.error; }
|
|
811
1237
|
}
|
|
812
1238
|
return null;
|
|
813
1239
|
}
|
|
@@ -827,6 +1253,93 @@ function resolveOpenAISettings(config) {
|
|
|
827
1253
|
retryDelayMs: normalizeOptionalNumber(serverConfig['OPENAI_RETRY_DELAY_MS'] || process.env.OPENAI_RETRY_DELAY_MS)
|
|
828
1254
|
};
|
|
829
1255
|
}
|
|
1256
|
+
function buildAiFormSystemPrompt() {
|
|
1257
|
+
return AI_FORM_PATCH_SYSTEM_PROMPT;
|
|
1258
|
+
}
|
|
1259
|
+
function buildAiFormUserPrompt(message, fields, patchFormat, route) {
|
|
1260
|
+
var lines = [];
|
|
1261
|
+
lines.push("User request: ".concat(message));
|
|
1262
|
+
var normalizedRoute = normalizeOptionalString(route);
|
|
1263
|
+
if (normalizedRoute) {
|
|
1264
|
+
lines.push("Current route: ".concat(normalizedRoute));
|
|
1265
|
+
}
|
|
1266
|
+
if (patchFormat) {
|
|
1267
|
+
lines.push('Patch format:');
|
|
1268
|
+
lines.push(patchFormat);
|
|
1269
|
+
}
|
|
1270
|
+
lines.push('Allowed fields:');
|
|
1271
|
+
fields.forEach(function (field) {
|
|
1272
|
+
var name = field.name || '';
|
|
1273
|
+
if (!name) {
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
var parts = [name];
|
|
1277
|
+
if (field.type) {
|
|
1278
|
+
parts.push("type=".concat(field.type));
|
|
1279
|
+
}
|
|
1280
|
+
if (field.label) {
|
|
1281
|
+
parts.push("label=\"".concat(field.label, "\""));
|
|
1282
|
+
}
|
|
1283
|
+
if (Array.isArray(field.enums) && field.enums.length) {
|
|
1284
|
+
parts.push("enums=".concat(field.enums.join('|')));
|
|
1285
|
+
}
|
|
1286
|
+
lines.push("- ".concat(parts.join(' ')));
|
|
1287
|
+
});
|
|
1288
|
+
lines.push('Return JSON only.');
|
|
1289
|
+
return lines.join('\n');
|
|
1290
|
+
}
|
|
1291
|
+
function normalizeAiFormFields(fields) {
|
|
1292
|
+
if (!Array.isArray(fields)) {
|
|
1293
|
+
return [];
|
|
1294
|
+
}
|
|
1295
|
+
return fields
|
|
1296
|
+
.map(function (field) {
|
|
1297
|
+
if (!field || typeof field !== 'object') {
|
|
1298
|
+
return null;
|
|
1299
|
+
}
|
|
1300
|
+
var name = normalizeOptionalString(field.name) || normalizeOptionalString(field.path);
|
|
1301
|
+
if (!name) {
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
var type = normalizeOptionalString(field.type);
|
|
1305
|
+
var label = normalizeOptionalString(field.label);
|
|
1306
|
+
var enums = Array.isArray(field.enums)
|
|
1307
|
+
? field.enums.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
|
|
1308
|
+
: undefined;
|
|
1309
|
+
var normalizedField = { name: name };
|
|
1310
|
+
if (type) {
|
|
1311
|
+
normalizedField.type = type;
|
|
1312
|
+
}
|
|
1313
|
+
if (label) {
|
|
1314
|
+
normalizedField.label = label;
|
|
1315
|
+
}
|
|
1316
|
+
if (enums && enums.length) {
|
|
1317
|
+
normalizedField.enums = enums;
|
|
1318
|
+
}
|
|
1319
|
+
return normalizedField;
|
|
1320
|
+
})
|
|
1321
|
+
.filter(function (field) { return !!field; });
|
|
1322
|
+
}
|
|
1323
|
+
function parseJsonObject(content) {
|
|
1324
|
+
if (!content || typeof content !== 'string') {
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
try {
|
|
1328
|
+
return JSON.parse(content);
|
|
1329
|
+
}
|
|
1330
|
+
catch (_a) {
|
|
1331
|
+
var match = content.match(/\{[\s\S]*\}/);
|
|
1332
|
+
if (!match) {
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1335
|
+
try {
|
|
1336
|
+
return JSON.parse(match[0]);
|
|
1337
|
+
}
|
|
1338
|
+
catch (_b) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
830
1343
|
function resolveUploadLimits() {
|
|
831
1344
|
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
832
1345
|
var maxFileMb = normalizeOptionalNumber(config['AI_TERMINAL_MAX_FILE_MB'] || process.env.AI_TERMINAL_MAX_FILE_MB) || DEFAULT_MAX_FILE_MB;
|
|
@@ -884,8 +1397,8 @@ function handleCodexUpload(id_conversation, file_name, content_base64, size, con
|
|
|
884
1397
|
}
|
|
885
1398
|
function readAttachmentContents(attachments) {
|
|
886
1399
|
return __awaiter(this, void 0, void 0, function () {
|
|
887
|
-
var limits, totalBytes, totalChars, chunks, cleaned, attachments_1, attachments_1_1, attachment, localPath, safe, stat, ext, name_1, type, readable, content, _a,
|
|
888
|
-
var
|
|
1400
|
+
var limits, totalBytes, totalChars, chunks, cleaned, attachments_1, attachments_1_1, attachment, localPath, safe, stat, ext, name_1, type, readable, content, _a, e_3_1;
|
|
1401
|
+
var e_3, _b;
|
|
889
1402
|
return __generator(this, function (_c) {
|
|
890
1403
|
switch (_c.label) {
|
|
891
1404
|
case 0:
|
|
@@ -964,14 +1477,14 @@ function readAttachmentContents(attachments) {
|
|
|
964
1477
|
return [3 /*break*/, 2];
|
|
965
1478
|
case 10: return [3 /*break*/, 13];
|
|
966
1479
|
case 11:
|
|
967
|
-
|
|
968
|
-
|
|
1480
|
+
e_3_1 = _c.sent();
|
|
1481
|
+
e_3 = { error: e_3_1 };
|
|
969
1482
|
return [3 /*break*/, 13];
|
|
970
1483
|
case 12:
|
|
971
1484
|
try {
|
|
972
1485
|
if (attachments_1_1 && !attachments_1_1.done && (_b = attachments_1.return)) _b.call(attachments_1);
|
|
973
1486
|
}
|
|
974
|
-
finally { if (
|
|
1487
|
+
finally { if (e_3) throw e_3.error; }
|
|
975
1488
|
return [7 /*endfinally*/];
|
|
976
1489
|
case 13: return [2 /*return*/, {
|
|
977
1490
|
promptText: chunks.length ? "\n\nAttachments:\n".concat(chunks.join('\n\n')) : '',
|
|
@@ -1124,10 +1637,11 @@ function estimateUsage(messages, responseText, model) {
|
|
|
1124
1637
|
};
|
|
1125
1638
|
}
|
|
1126
1639
|
function evaluateGuardrails(message) {
|
|
1127
|
-
var
|
|
1640
|
+
var e_4, _a;
|
|
1128
1641
|
var normalized = String(message || '').toLowerCase();
|
|
1129
1642
|
var patterns = [
|
|
1130
1643
|
{ 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.' },
|
|
1644
|
+
{ pattern: /\b(show|share|paste|provide|dump|output)\b.*\b(code|file|contents|snippet)\b/i, reason: 'Code access is restricted.' },
|
|
1131
1645
|
{ pattern: /\b(credentials?|passwords?|secrets?|tokens?)\b/i, reason: 'Credentials and secrets are restricted.' },
|
|
1132
1646
|
{ pattern: /\b(delete|drop)\s+(database|db|schema)\b/i, reason: 'Database operations are restricted.' },
|
|
1133
1647
|
{ pattern: /\b(shell|terminal|ssh|sudo|rm\s+-rf|chmod|chown)\b/i, reason: 'Server operations are restricted.' },
|
|
@@ -1140,17 +1654,17 @@ function evaluateGuardrails(message) {
|
|
|
1140
1654
|
return {
|
|
1141
1655
|
blocked: true,
|
|
1142
1656
|
reason: entry.reason,
|
|
1143
|
-
response: 'I can’t help with that request because it could
|
|
1657
|
+
response: 'I can’t help with that request because it could expose proprietary code or protected information. If you need a change, describe the outcome and I can help within approved workflows.'
|
|
1144
1658
|
};
|
|
1145
1659
|
}
|
|
1146
1660
|
}
|
|
1147
1661
|
}
|
|
1148
|
-
catch (
|
|
1662
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
1149
1663
|
finally {
|
|
1150
1664
|
try {
|
|
1151
1665
|
if (patterns_2_1 && !patterns_2_1.done && (_a = patterns_2.return)) _a.call(patterns_2);
|
|
1152
1666
|
}
|
|
1153
|
-
finally { if (
|
|
1667
|
+
finally { if (e_4) throw e_4.error; }
|
|
1154
1668
|
}
|
|
1155
1669
|
return null;
|
|
1156
1670
|
}
|