@resolveio/server-lib 22.0.10 → 22.0.11
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.js +300 -66
- package/methods/ai-terminal.js.map +1 -1
- package/methods/report-builder.js +34 -8
- package/methods/report-builder.js.map +1 -1
- package/package.json +1 -1
- package/services/codex-client.d.ts +10 -0
- package/services/codex-client.js +124 -19
- package/services/codex-client.js.map +1 -1
package/methods/ai-terminal.js
CHANGED
|
@@ -139,7 +139,8 @@ var DEFAULT_MAX_FILE_MB = 50;
|
|
|
139
139
|
var DEFAULT_MAX_TOTAL_MB = 100;
|
|
140
140
|
var DEFAULT_MAX_ATTACHMENT_CHARS = 12000;
|
|
141
141
|
var DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS = 40000;
|
|
142
|
-
var DEFAULT_CODEX_MODEL = 'gpt-5.
|
|
142
|
+
var DEFAULT_CODEX_MODEL = 'gpt-5.3-codex';
|
|
143
|
+
var DEFAULT_CODEX_FALLBACK_MODEL = 'gpt-5.2-codex';
|
|
143
144
|
var DEFAULT_CODEX_TIMEOUT_MS = 180000;
|
|
144
145
|
var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
|
|
145
146
|
var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
|
|
@@ -381,12 +382,13 @@ var AI_ASSISTANT_REPORT_BUILDER_EXPERT_PLAYBOOK = [
|
|
|
381
382
|
'',
|
|
382
383
|
'2) Resolve the target dataset safely.',
|
|
383
384
|
'- Map user wording to internal collection names using routes, collection hints, field hints, and synonym expansion.',
|
|
384
|
-
'- Prefer report-* collections when permissionView is under /report.',
|
|
385
|
+
'- Prefer report-* collections when permissionView is under /report-builder.',
|
|
385
386
|
'- Never use *.versions unless user explicitly requests bug-history/version investigation.',
|
|
386
387
|
'- Never invent collection names or fields.',
|
|
387
388
|
'',
|
|
388
389
|
'3) Enforce permissions and scope in the directive.',
|
|
389
390
|
'- Always include permissionView.',
|
|
391
|
+
'- Use /report-builder as the default permissionView for data directives; avoid /report/* routes.',
|
|
390
392
|
'- Assume non-super-admin unless explicitly told otherwise.',
|
|
391
393
|
'- Invoice-like collections require invoice view access.',
|
|
392
394
|
'- Customer portal users must stay in their own customer scope.',
|
|
@@ -435,7 +437,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
435
437
|
'- Step 1 (always): determine the target collections/models/modules/workflows using context, routes, and collection hints. Assume the user is non-technical and will not provide internal names.',
|
|
436
438
|
'- Never use *.versions collections for normal requests. Only use a .versions collection when explicitly investigating a bug by checking the last ~5 updates.',
|
|
437
439
|
'- Planning stage: regex/keyword scan the codebase for collectionName/model definitions, methods, publications, and Angular routes/modules to map user wording to internal names.',
|
|
438
|
-
'- If permissionView starts with /report
|
|
440
|
+
'- If permissionView starts with /report-builder, prefer the report-* collection when both report and base collections exist.',
|
|
439
441
|
'- Map user wording to internal collections/fields yourself. Do not ask for property names unless required to run a query.',
|
|
440
442
|
'- Use term hints from context (synonym expansions) when mapping user language to collections.',
|
|
441
443
|
'- Do not guess or invent collections/fields. If unsure, verify in the codebase or run a small REPORT_BUILDER_READ probe (limit 1-5) to learn the shape.',
|
|
@@ -490,7 +492,8 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
490
492
|
'- REPORT_BUILDER_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
|
|
491
493
|
'- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
|
|
492
494
|
'- REPORT_BUILDER_AGG: {"collection":"<name>","pipeline":[...],"options":{"allowDiskUse":true,"limit":20},"permissionView":"</route>"}',
|
|
493
|
-
'- For invoice data, set permissionView to an invoice route (ex: /invoice/list or /report/
|
|
495
|
+
'- For invoice data, set permissionView to an invoice-capable route (ex: /invoice/list or /report-builder/list).',
|
|
496
|
+
'- Do not use /report/* routes as permissionView for data directives; use /report-builder or a module route.',
|
|
494
497
|
'- For revenue/sales/billing questions, use invoices and sum paid_total (fallback to grand_total) with date_paid and Paid/Closed status when available.',
|
|
495
498
|
'- For revenue answers, always state the metric/date basis used (paid_total/date_paid vs grand_total/date_invoice). If tool verification warns about ambiguity or partial months, call that out before totals.',
|
|
496
499
|
'- For relative date ranges (last/past/recent), include an upper bound <= $$NOW unless the user specifies a future end date.',
|
|
@@ -532,7 +535,7 @@ var AI_ASSISTANT_PLANNER_SYSTEM_PROMPT = [
|
|
|
532
535
|
' - Never propose querying blocked/sensitive collections if the user lacks permission.',
|
|
533
536
|
'',
|
|
534
537
|
'4) PERMISSION MATCHING:',
|
|
535
|
-
' - Do NOT hardcode invoice access to "/report
|
|
538
|
+
' - Do NOT hardcode invoice access to "/report-builder/*".',
|
|
536
539
|
' - For invoice-related data or navigation, permission is satisfied if ANY user view contains "invoice" case-insensitive.',
|
|
537
540
|
' (General rule: for an entity token X, permission is satisfied if any view contains X case-insensitive.)',
|
|
538
541
|
' - If permission checks are ambiguous, choose the safest restriction and explain.',
|
|
@@ -667,7 +670,7 @@ var AI_FORM_PATCH_SYSTEM_PROMPT = [
|
|
|
667
670
|
'- Use ISO 8601 for dates and true/false for booleans.',
|
|
668
671
|
'- Use medium reasoning effort.'
|
|
669
672
|
].join('\n');
|
|
670
|
-
var
|
|
673
|
+
var assistantCodexClientByConfig = new Map();
|
|
671
674
|
var assistantCodexRunQueue = [];
|
|
672
675
|
var assistantCodexRunDraining = false;
|
|
673
676
|
/* eslint-enable no-unused-vars */
|
|
@@ -1320,7 +1323,7 @@ function executeAiFormPatch(payload, context) {
|
|
|
1320
1323
|
}
|
|
1321
1324
|
function executeAiAssistantCodexRun(payload, context) {
|
|
1322
1325
|
return __awaiter(this, void 0, void 0, function () {
|
|
1323
|
-
var input, message, aiWorkerDebug, requestId, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, userDoc, initialProgress, assistantDoc, insertResult, assistantMessageId;
|
|
1326
|
+
var input, message, aiWorkerDebug, requestId, codexModel, codexFallbackModels, guardrail, conversation_2, now_2, userMsg, assistantMsg, user, isSuperAdmin, hasInvoiceAccess, customerId, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, recentToolError, userDoc, initialProgress, assistantDoc, insertResult, assistantMessageId;
|
|
1324
1327
|
var _this = this;
|
|
1325
1328
|
var _b, _c;
|
|
1326
1329
|
return __generator(this, function (_d) {
|
|
@@ -1336,6 +1339,8 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1336
1339
|
}
|
|
1337
1340
|
aiWorkerDebug = isAiWorkerDebugEnabled();
|
|
1338
1341
|
requestId = normalizeOptionalString(input.request_id);
|
|
1342
|
+
codexModel = resolveCodexModel(input.config);
|
|
1343
|
+
codexFallbackModels = resolveCodexFallbackModels(input.config, codexModel);
|
|
1339
1344
|
guardrail = evaluateAssistantGuardrails(message);
|
|
1340
1345
|
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
|
|
1341
1346
|
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
@@ -1415,6 +1420,9 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1415
1420
|
historyLines.push("".concat(role, ": ").concat(content));
|
|
1416
1421
|
}
|
|
1417
1422
|
});
|
|
1423
|
+
recentToolError = isAssistantWhyFollowupMessage(message)
|
|
1424
|
+
? resolveRecentAssistantToolError(history)
|
|
1425
|
+
: '';
|
|
1418
1426
|
userDoc = {
|
|
1419
1427
|
id_conversation: conversation._id,
|
|
1420
1428
|
role: 'user',
|
|
@@ -1429,7 +1437,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1429
1437
|
id_conversation: conversation._id,
|
|
1430
1438
|
role: 'assistant',
|
|
1431
1439
|
content: AI_ASSISTANT_PROGRESS_PLACEHOLDER,
|
|
1432
|
-
metadata: __assign(__assign({ model:
|
|
1440
|
+
metadata: __assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), { pending: true, progress: initialProgress }),
|
|
1433
1441
|
createdAt: now,
|
|
1434
1442
|
updatedAt: now
|
|
1435
1443
|
};
|
|
@@ -1564,16 +1572,22 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1564
1572
|
customerId: customerId,
|
|
1565
1573
|
collectionHints: collectionHints,
|
|
1566
1574
|
termHints: termHints,
|
|
1567
|
-
fieldHints: fieldHints
|
|
1575
|
+
fieldHints: fieldHints,
|
|
1576
|
+
recentToolError: recentToolError
|
|
1568
1577
|
});
|
|
1569
1578
|
prompt_1 = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
|
|
1570
1579
|
return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
|
|
1571
1580
|
case 6:
|
|
1572
1581
|
workspaceRoot = _x.sent();
|
|
1573
|
-
codexConfig = resolveCodexSettings(
|
|
1582
|
+
codexConfig = resolveCodexSettings({
|
|
1583
|
+
model: codexModel,
|
|
1584
|
+
fallbackModels: codexFallbackModels
|
|
1585
|
+
});
|
|
1574
1586
|
runOptions = {
|
|
1575
1587
|
timeoutMs: resolveCodexTimeoutMs(),
|
|
1588
|
+
fallbackModels: codexFallbackModels,
|
|
1576
1589
|
threadOptions: {
|
|
1590
|
+
model: codexModel,
|
|
1577
1591
|
workingDirectory: workspaceRoot,
|
|
1578
1592
|
sandboxMode: 'read-only',
|
|
1579
1593
|
skipGitRepoCheck: true,
|
|
@@ -1874,7 +1888,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1874
1888
|
}
|
|
1875
1889
|
});
|
|
1876
1890
|
}
|
|
1877
|
-
finalMetadata = __assign(__assign(__assign({ model:
|
|
1891
|
+
finalMetadata = __assign(__assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), (toolResult ? { tool_result: toolResult } : {})), (assistantDebug ? { debug: assistantDebug } : {}));
|
|
1878
1892
|
finalAssistantDoc = __assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata, updatedAt: finalNow });
|
|
1879
1893
|
if (!assistantMessageId) return [3 /*break*/, 39];
|
|
1880
1894
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: assistantMessageId }, {
|
|
@@ -3548,13 +3562,12 @@ function extractAssistantMongoDirective(content) {
|
|
|
3548
3562
|
};
|
|
3549
3563
|
}
|
|
3550
3564
|
function buildAssistantToolRequest(directive, payload) {
|
|
3551
|
-
var _a;
|
|
3552
3565
|
var base = directive.payload && typeof directive.payload === 'object' ? directive.payload : {};
|
|
3553
3566
|
var request = __assign({}, base);
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
request.permissionView = route;
|
|
3567
|
+
if (!request.permissionView) {
|
|
3568
|
+
request.permissionView = '/report-builder';
|
|
3557
3569
|
}
|
|
3570
|
+
request.permissionView = normalizeAssistantPermissionView(request.permissionView, request.collection);
|
|
3558
3571
|
if (!request.id_client) {
|
|
3559
3572
|
var idClient = normalizeOptionalString(payload === null || payload === void 0 ? void 0 : payload.id_client);
|
|
3560
3573
|
if (idClient) {
|
|
@@ -3566,6 +3579,24 @@ function buildAssistantToolRequest(directive, payload) {
|
|
|
3566
3579
|
}
|
|
3567
3580
|
return request;
|
|
3568
3581
|
}
|
|
3582
|
+
function normalizeAssistantPermissionView(permissionView, collection) {
|
|
3583
|
+
var normalizedPermission = normalizeOptionalString(permissionView);
|
|
3584
|
+
var normalizedCollection = normalizeOptionalString(collection);
|
|
3585
|
+
var loweredPermission = normalizedPermission.toLowerCase();
|
|
3586
|
+
if (!normalizedPermission) {
|
|
3587
|
+
return '/report-builder';
|
|
3588
|
+
}
|
|
3589
|
+
if (loweredPermission === '/report-builder' || loweredPermission.startsWith('/report-builder/')) {
|
|
3590
|
+
return '/report-builder';
|
|
3591
|
+
}
|
|
3592
|
+
if (loweredPermission === '/report' || loweredPermission.startsWith('/report/')) {
|
|
3593
|
+
if (requiresInvoicePermission(normalizedCollection)) {
|
|
3594
|
+
return '/invoice/list';
|
|
3595
|
+
}
|
|
3596
|
+
return '/report-builder';
|
|
3597
|
+
}
|
|
3598
|
+
return normalizedPermission;
|
|
3599
|
+
}
|
|
3569
3600
|
function buildAssistantToolResultPayload(directive, toolResponse) {
|
|
3570
3601
|
var _a, _b, _c;
|
|
3571
3602
|
var directivePayload = directive.payload || {};
|
|
@@ -3877,7 +3908,7 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
3877
3908
|
? "Open ".concat(routeHint, " in the app to view this data or request access.")
|
|
3878
3909
|
: 'Open the related screen in the app to view this data or request access.';
|
|
3879
3910
|
if (!routeHint && collection && requiresInvoicePermission(collection)) {
|
|
3880
|
-
routeLine = 'Open /invoice/list or /report/
|
|
3911
|
+
routeLine = 'Open /invoice/list or /report-builder/list to view this data or request access.';
|
|
3881
3912
|
}
|
|
3882
3913
|
if (normalized.includes('permission scope required')) {
|
|
3883
3914
|
return "I need a permission scope to access that data. ".concat(routeLine);
|
|
@@ -3891,6 +3922,9 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
3891
3922
|
if (normalized.includes('database access denied')) {
|
|
3892
3923
|
return "Database access is restricted for that request. ".concat(routeLine);
|
|
3893
3924
|
}
|
|
3925
|
+
if (normalized.includes('undefined variable') && normalized.includes('now_minus')) {
|
|
3926
|
+
return "The query used an unsupported relative date token. Please retry; the assistant now normalizes relative dates automatically. ".concat(routeLine);
|
|
3927
|
+
}
|
|
3894
3928
|
if (normalized.includes('report builder bridge') && normalized.includes('not configured')) {
|
|
3895
3929
|
return "That dataset is not configured for report builder access yet. ".concat(routeLine);
|
|
3896
3930
|
}
|
|
@@ -5595,7 +5629,7 @@ function isDisplayObjectLike(value) {
|
|
|
5595
5629
|
}
|
|
5596
5630
|
function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
5597
5631
|
return __awaiter(this, void 0, void 0, function () {
|
|
5598
|
-
var idUser, user, isSuperAdmin, normalizedPermission,
|
|
5632
|
+
var idUser, user, isSuperAdmin, normalizedCollection, normalizedPermission, requiresInvoiceAccess, hasInvoiceAccess, hasViewAccess;
|
|
5599
5633
|
var _a;
|
|
5600
5634
|
return __generator(this, function (_b) {
|
|
5601
5635
|
switch (_b.label) {
|
|
@@ -5611,20 +5645,21 @@ function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
|
5611
5645
|
throw new Error('AI assistant report builder bridge: Unauthorized.');
|
|
5612
5646
|
}
|
|
5613
5647
|
isSuperAdmin = !!((_a = user === null || user === void 0 ? void 0 : user.roles) === null || _a === void 0 ? void 0 : _a.super_admin);
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
if (!normalizedPermission) {
|
|
5617
|
-
throw new Error('AI assistant report builder bridge: Permission scope required.');
|
|
5618
|
-
}
|
|
5619
|
-
if (!userHasViewPermission(user, normalizedPermission)) {
|
|
5620
|
-
throw new Error('AI assistant report builder bridge: Access denied.');
|
|
5621
|
-
}
|
|
5622
|
-
normalizedCollection = normalizeOptionalString(collection);
|
|
5623
|
-
if (normalizedCollection && requiresInvoicePermission(normalizedCollection) && !userHasInvoiceAccess(user)) {
|
|
5624
|
-
throw new Error('AI assistant report builder bridge: Access denied.');
|
|
5625
|
-
}
|
|
5648
|
+
if (isSuperAdmin) {
|
|
5649
|
+
return [2 /*return*/, { user: user, isSuperAdmin: isSuperAdmin }];
|
|
5626
5650
|
}
|
|
5627
|
-
|
|
5651
|
+
normalizedCollection = normalizeOptionalString(collection);
|
|
5652
|
+
normalizedPermission = normalizeAssistantPermissionView(permissionView, normalizedCollection);
|
|
5653
|
+
if (!normalizedPermission) {
|
|
5654
|
+
throw new Error('AI assistant report builder bridge: Permission scope required.');
|
|
5655
|
+
}
|
|
5656
|
+
requiresInvoiceAccess = normalizedCollection ? requiresInvoicePermission(normalizedCollection) : false;
|
|
5657
|
+
hasInvoiceAccess = requiresInvoiceAccess && userHasInvoiceAccess(user);
|
|
5658
|
+
hasViewAccess = userHasViewPermission(user, normalizedPermission);
|
|
5659
|
+
if (!hasViewAccess && !hasInvoiceAccess) {
|
|
5660
|
+
throw new Error('AI assistant report builder bridge: Access denied.');
|
|
5661
|
+
}
|
|
5662
|
+
if (requiresInvoiceAccess && !hasInvoiceAccess) {
|
|
5628
5663
|
throw new Error('AI assistant report builder bridge: Access denied.');
|
|
5629
5664
|
}
|
|
5630
5665
|
return [2 /*return*/, { user: user, isSuperAdmin: isSuperAdmin }];
|
|
@@ -5700,6 +5735,90 @@ function sanitizeAssistantProjection(projection) {
|
|
|
5700
5735
|
return projection;
|
|
5701
5736
|
}
|
|
5702
5737
|
var AGG_MATCH_EXPR_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte']);
|
|
5738
|
+
var ASSISTANT_NOW_RELATIVE_PATTERN = /^\$\$NOW_(MINUS|PLUS)_([0-9]+)_(MINUTES?|HOURS?|DAYS?|WEEKS?|MONTHS?|YEARS?)$/i;
|
|
5739
|
+
function normalizeAssistantTimeUnit(raw) {
|
|
5740
|
+
var normalized = String(raw || '').toLowerCase();
|
|
5741
|
+
if (normalized.startsWith('minute')) {
|
|
5742
|
+
return 'minute';
|
|
5743
|
+
}
|
|
5744
|
+
if (normalized.startsWith('hour')) {
|
|
5745
|
+
return 'hour';
|
|
5746
|
+
}
|
|
5747
|
+
if (normalized.startsWith('day')) {
|
|
5748
|
+
return 'day';
|
|
5749
|
+
}
|
|
5750
|
+
if (normalized.startsWith('week')) {
|
|
5751
|
+
return 'week';
|
|
5752
|
+
}
|
|
5753
|
+
if (normalized.startsWith('month')) {
|
|
5754
|
+
return 'month';
|
|
5755
|
+
}
|
|
5756
|
+
return 'year';
|
|
5757
|
+
}
|
|
5758
|
+
function parseAssistantNowRelativeToken(value) {
|
|
5759
|
+
var trimmed = normalizeOptionalString(value);
|
|
5760
|
+
if (!trimmed) {
|
|
5761
|
+
return null;
|
|
5762
|
+
}
|
|
5763
|
+
var match = trimmed.match(ASSISTANT_NOW_RELATIVE_PATTERN);
|
|
5764
|
+
if (!match) {
|
|
5765
|
+
return null;
|
|
5766
|
+
}
|
|
5767
|
+
var direction = String(match[1] || '').toUpperCase() === 'PLUS' ? 'PLUS' : 'MINUS';
|
|
5768
|
+
var amount = Number(match[2]);
|
|
5769
|
+
if (!Number.isFinite(amount) || amount < 0) {
|
|
5770
|
+
return null;
|
|
5771
|
+
}
|
|
5772
|
+
var unit = normalizeAssistantTimeUnit(match[3] || '');
|
|
5773
|
+
return {
|
|
5774
|
+
operator: direction === 'PLUS' ? '$dateAdd' : '$dateSubtract',
|
|
5775
|
+
amount: amount,
|
|
5776
|
+
unit: unit
|
|
5777
|
+
};
|
|
5778
|
+
}
|
|
5779
|
+
function normalizeAssistantNowExprOperand(value) {
|
|
5780
|
+
var _a;
|
|
5781
|
+
if (typeof value !== 'string') {
|
|
5782
|
+
return value;
|
|
5783
|
+
}
|
|
5784
|
+
var trimmed = normalizeOptionalString(value);
|
|
5785
|
+
if (!trimmed) {
|
|
5786
|
+
return value;
|
|
5787
|
+
}
|
|
5788
|
+
if (trimmed === '$$NOW') {
|
|
5789
|
+
return '$$NOW';
|
|
5790
|
+
}
|
|
5791
|
+
var parsed = parseAssistantNowRelativeToken(trimmed);
|
|
5792
|
+
if (!parsed) {
|
|
5793
|
+
return value;
|
|
5794
|
+
}
|
|
5795
|
+
return _a = {},
|
|
5796
|
+
_a[parsed.operator] = {
|
|
5797
|
+
startDate: '$$NOW',
|
|
5798
|
+
unit: parsed.unit,
|
|
5799
|
+
amount: parsed.amount
|
|
5800
|
+
},
|
|
5801
|
+
_a;
|
|
5802
|
+
}
|
|
5803
|
+
function normalizeAssistantNowExprPlaceholdersDeep(value) {
|
|
5804
|
+
if (Array.isArray(value)) {
|
|
5805
|
+
return value.map(function (entry) { return normalizeAssistantNowExprPlaceholdersDeep(entry); });
|
|
5806
|
+
}
|
|
5807
|
+
if (value instanceof Date || value instanceof RegExp || isMongoObjectId(value)) {
|
|
5808
|
+
return value;
|
|
5809
|
+
}
|
|
5810
|
+
if (typeof value === 'string') {
|
|
5811
|
+
return normalizeAssistantNowExprOperand(value);
|
|
5812
|
+
}
|
|
5813
|
+
if (!value || typeof value !== 'object') {
|
|
5814
|
+
return value;
|
|
5815
|
+
}
|
|
5816
|
+
var result = {};
|
|
5817
|
+
Object.keys(value).forEach(function (key) {
|
|
5818
|
+
result[key] = normalizeAssistantNowExprPlaceholdersDeep(value[key]);
|
|
5819
|
+
});
|
|
5820
|
+
return result;
|
|
5821
|
+
}
|
|
5703
5822
|
function isMatchExpressionOperand(value) {
|
|
5704
5823
|
if (typeof value === 'string') {
|
|
5705
5824
|
return value.startsWith('$$');
|
|
@@ -5757,7 +5876,7 @@ function rewriteMatchExpressionsToExpr(match) {
|
|
|
5757
5876
|
}
|
|
5758
5877
|
var operand = nextEntry_1[op];
|
|
5759
5878
|
if (isMatchExpressionOperand(operand)) {
|
|
5760
|
-
exprClauses.push((_a = {}, _a[op] = ["$".concat(key), operand], _a));
|
|
5879
|
+
exprClauses.push((_a = {}, _a[op] = ["$".concat(key), normalizeAssistantNowExprOperand(operand)], _a));
|
|
5761
5880
|
delete nextEntry_1[op];
|
|
5762
5881
|
moved_1 = true;
|
|
5763
5882
|
}
|
|
@@ -5771,7 +5890,7 @@ function rewriteMatchExpressionsToExpr(match) {
|
|
|
5771
5890
|
return;
|
|
5772
5891
|
}
|
|
5773
5892
|
if (typeof entry === 'string' && entry.startsWith('$$')) {
|
|
5774
|
-
exprClauses.push({ $eq: ["$".concat(key), entry] });
|
|
5893
|
+
exprClauses.push({ $eq: ["$".concat(key), normalizeAssistantNowExprOperand(entry)] });
|
|
5775
5894
|
return;
|
|
5776
5895
|
}
|
|
5777
5896
|
result[key] = entry;
|
|
@@ -5848,7 +5967,7 @@ function normalizeAssistantAggregatePipeline(pipeline, collection) {
|
|
|
5848
5967
|
var statusNormalized = isInvoiceCollection ? normalizeInvoiceStatusMatch(exprRewritten) : exprRewritten;
|
|
5849
5968
|
next.$geoNear = __assign(__assign({}, next.$geoNear), { query: applyAssistantNameRegexToQuery(statusNormalized) });
|
|
5850
5969
|
}
|
|
5851
|
-
return next;
|
|
5970
|
+
return normalizeAssistantNowExprPlaceholdersDeep(next);
|
|
5852
5971
|
});
|
|
5853
5972
|
}
|
|
5854
5973
|
function buildAssistantAggregatePipeline(query, pipeline) {
|
|
@@ -7495,7 +7614,9 @@ function normalizeMongoQuery(query) {
|
|
|
7495
7614
|
throw new Error('AI assistant report builder bridge: Query contains restricted operators.');
|
|
7496
7615
|
}
|
|
7497
7616
|
var rewritten = rewriteEmbeddedMatchObjects(normalized);
|
|
7498
|
-
|
|
7617
|
+
var exprRewritten = rewriteMatchExpressionsToExpr(rewritten);
|
|
7618
|
+
var nowNormalized = normalizeAssistantNowExprPlaceholdersDeep(exprRewritten);
|
|
7619
|
+
return applyAssistantNameRegexToQuery(nowNormalized);
|
|
7499
7620
|
}
|
|
7500
7621
|
function shouldApplyAssistantNameRegex(field) {
|
|
7501
7622
|
var normalized = String(field || '').toLowerCase().trim();
|
|
@@ -8019,7 +8140,7 @@ function shouldAllowVersionCollections(message) {
|
|
|
8019
8140
|
}
|
|
8020
8141
|
function resolveReportCollectionName(permissionView, collectionNames, currentCollection) {
|
|
8021
8142
|
var normalizedView = normalizeOptionalString(permissionView).toLowerCase();
|
|
8022
|
-
if (!normalizedView.startsWith('/report
|
|
8143
|
+
if (!normalizedView.startsWith('/report-builder')) {
|
|
8023
8144
|
return null;
|
|
8024
8145
|
}
|
|
8025
8146
|
var current = stripVersionSuffix(normalizeOptionalString(currentCollection));
|
|
@@ -8027,11 +8148,6 @@ function resolveReportCollectionName(permissionView, collectionNames, currentCol
|
|
|
8027
8148
|
if (collectionNames.includes(reportCollection)) {
|
|
8028
8149
|
return reportCollection;
|
|
8029
8150
|
}
|
|
8030
|
-
var routeTail = normalizedView.replace('/report/', '').replace(/\//g, '-');
|
|
8031
|
-
var routeCandidate = routeTail ? "report-".concat(routeTail) : '';
|
|
8032
|
-
if (routeCandidate && collectionNames.includes(routeCandidate)) {
|
|
8033
|
-
return routeCandidate;
|
|
8034
|
-
}
|
|
8035
8151
|
return null;
|
|
8036
8152
|
}
|
|
8037
8153
|
function resolveBaseCollectionFromReport(db, dbName, collection) {
|
|
@@ -8069,7 +8185,7 @@ function resolveCollectionOverrideWithContext(params) {
|
|
|
8069
8185
|
to: reportPreferred,
|
|
8070
8186
|
fromScore: 0,
|
|
8071
8187
|
toScore: 0,
|
|
8072
|
-
reason: 'report route preference'
|
|
8188
|
+
reason: 'report builder route preference'
|
|
8073
8189
|
};
|
|
8074
8190
|
}
|
|
8075
8191
|
}
|
|
@@ -8677,14 +8793,43 @@ function userHasViewPermission(user, view) {
|
|
|
8677
8793
|
}
|
|
8678
8794
|
return false;
|
|
8679
8795
|
}
|
|
8680
|
-
function
|
|
8681
|
-
|
|
8796
|
+
function collectUserViewPermissions(user) {
|
|
8797
|
+
var _a, _b;
|
|
8798
|
+
if (!user) {
|
|
8799
|
+
return [];
|
|
8800
|
+
}
|
|
8801
|
+
var groups = Array.isArray((_a = user.roles) === null || _a === void 0 ? void 0 : _a.groups) ? user.roles.groups : [];
|
|
8802
|
+
var miscs = Array.isArray((_b = user.roles) === null || _b === void 0 ? void 0 : _b.miscs) ? user.roles.miscs : [];
|
|
8803
|
+
var collected = [];
|
|
8804
|
+
var seen = new Set();
|
|
8805
|
+
var push = function (value) {
|
|
8806
|
+
var normalized = normalizeOptionalString(value);
|
|
8807
|
+
if (!normalized || seen.has(normalized)) {
|
|
8808
|
+
return;
|
|
8809
|
+
}
|
|
8810
|
+
seen.add(normalized);
|
|
8811
|
+
collected.push(normalized);
|
|
8812
|
+
};
|
|
8813
|
+
groups.forEach(function (group) {
|
|
8814
|
+
var views = Array.isArray(group === null || group === void 0 ? void 0 : group.views) ? group.views : [];
|
|
8815
|
+
views.forEach(push);
|
|
8816
|
+
});
|
|
8817
|
+
miscs.forEach(push);
|
|
8818
|
+
return collected;
|
|
8819
|
+
}
|
|
8820
|
+
function userHasViewTokenPermission(user, tokenRegex) {
|
|
8821
|
+
var _a;
|
|
8822
|
+
if (!user || !tokenRegex) {
|
|
8682
8823
|
return false;
|
|
8683
8824
|
}
|
|
8684
|
-
|
|
8825
|
+
if ((_a = user.roles) === null || _a === void 0 ? void 0 : _a.super_admin) {
|
|
8826
|
+
return true;
|
|
8827
|
+
}
|
|
8828
|
+
var permissions = collectUserViewPermissions(user);
|
|
8829
|
+
return permissions.some(function (view) { return tokenRegex.test(view); });
|
|
8685
8830
|
}
|
|
8686
8831
|
function userHasInvoiceAccess(user) {
|
|
8687
|
-
return
|
|
8832
|
+
return userHasViewTokenPermission(user, /invoice/i);
|
|
8688
8833
|
}
|
|
8689
8834
|
function requiresInvoicePermission(collection) {
|
|
8690
8835
|
var normalized = normalizeOptionalString(collection).toLowerCase();
|
|
@@ -8736,16 +8881,59 @@ function resolveCodexWorkerThreadEnabled() {
|
|
|
8736
8881
|
}
|
|
8737
8882
|
return process.env.IS_WORKER_INSTANCE !== 'true';
|
|
8738
8883
|
}
|
|
8739
|
-
function
|
|
8740
|
-
|
|
8741
|
-
|
|
8884
|
+
function normalizeCodexModelList(value) {
|
|
8885
|
+
if (Array.isArray(value)) {
|
|
8886
|
+
return value
|
|
8887
|
+
.map(function (entry) { return normalizeOptionalString(entry); })
|
|
8888
|
+
.filter(Boolean);
|
|
8889
|
+
}
|
|
8890
|
+
var raw = normalizeOptionalString(value);
|
|
8891
|
+
if (!raw) {
|
|
8892
|
+
return [];
|
|
8893
|
+
}
|
|
8894
|
+
return raw
|
|
8895
|
+
.split(',')
|
|
8896
|
+
.map(function (entry) { return normalizeOptionalString(entry); })
|
|
8897
|
+
.filter(Boolean);
|
|
8898
|
+
}
|
|
8899
|
+
function resolveCodexModel(config) {
|
|
8900
|
+
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8901
|
+
var raw = normalizeOptionalString((config === null || config === void 0 ? void 0 : config.model)
|
|
8902
|
+
|| (config === null || config === void 0 ? void 0 : config.codex_model)
|
|
8903
|
+
|| serverConfig['AI_ASSISTANT_CODEX_MODEL']
|
|
8742
8904
|
|| process.env.AI_ASSISTANT_CODEX_MODEL
|
|
8743
|
-
||
|
|
8905
|
+
|| serverConfig['AI_TERMINAL_CODEX_MODEL']
|
|
8744
8906
|
|| process.env.AI_TERMINAL_CODEX_MODEL
|
|
8745
|
-
||
|
|
8907
|
+
|| serverConfig['AI_DASHBOARD_CODEX_MODEL']
|
|
8746
8908
|
|| process.env.AI_DASHBOARD_CODEX_MODEL);
|
|
8747
8909
|
return raw || DEFAULT_CODEX_MODEL;
|
|
8748
8910
|
}
|
|
8911
|
+
function resolveCodexFallbackModels(config, primaryModel) {
|
|
8912
|
+
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8913
|
+
var primary = normalizeOptionalString(primaryModel || resolveCodexModel(config));
|
|
8914
|
+
var models = [];
|
|
8915
|
+
var push = function (value) {
|
|
8916
|
+
var normalized = normalizeOptionalString(value);
|
|
8917
|
+
if (!normalized || normalized === primary || models.includes(normalized)) {
|
|
8918
|
+
return;
|
|
8919
|
+
}
|
|
8920
|
+
models.push(normalized);
|
|
8921
|
+
};
|
|
8922
|
+
normalizeCodexModelList(config === null || config === void 0 ? void 0 : config.fallback_models).forEach(push);
|
|
8923
|
+
normalizeCodexModelList(config === null || config === void 0 ? void 0 : config.fallbackModels).forEach(push);
|
|
8924
|
+
push(config === null || config === void 0 ? void 0 : config.fallback_model);
|
|
8925
|
+
push(config === null || config === void 0 ? void 0 : config.fallbackModel);
|
|
8926
|
+
normalizeCodexModelList(serverConfig['AI_ASSISTANT_CODEX_FALLBACK_MODELS'] || process.env.AI_ASSISTANT_CODEX_FALLBACK_MODELS).forEach(push);
|
|
8927
|
+
push(serverConfig['AI_ASSISTANT_CODEX_FALLBACK_MODEL'] || process.env.AI_ASSISTANT_CODEX_FALLBACK_MODEL);
|
|
8928
|
+
normalizeCodexModelList(serverConfig['AI_TERMINAL_CODEX_FALLBACK_MODELS'] || process.env.AI_TERMINAL_CODEX_FALLBACK_MODELS).forEach(push);
|
|
8929
|
+
push(serverConfig['AI_TERMINAL_CODEX_FALLBACK_MODEL'] || process.env.AI_TERMINAL_CODEX_FALLBACK_MODEL);
|
|
8930
|
+
normalizeCodexModelList(serverConfig['AI_DASHBOARD_CODEX_FALLBACK_MODELS'] || process.env.AI_DASHBOARD_CODEX_FALLBACK_MODELS).forEach(push);
|
|
8931
|
+
push(serverConfig['AI_DASHBOARD_CODEX_FALLBACK_MODEL'] || process.env.AI_DASHBOARD_CODEX_FALLBACK_MODEL);
|
|
8932
|
+
if (!models.length) {
|
|
8933
|
+
push(DEFAULT_CODEX_FALLBACK_MODEL);
|
|
8934
|
+
}
|
|
8935
|
+
return models;
|
|
8936
|
+
}
|
|
8749
8937
|
function resolveCodexThoughtLevel() {
|
|
8750
8938
|
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8751
8939
|
var raw = normalizeOptionalString(config['AI_ASSISTANT_CODEX_THOUGHT_LEVEL']
|
|
@@ -8760,25 +8948,38 @@ function resolveCodexThoughtLevel() {
|
|
|
8760
8948
|
}
|
|
8761
8949
|
return 'low';
|
|
8762
8950
|
}
|
|
8763
|
-
function resolveCodexSettings() {
|
|
8951
|
+
function resolveCodexSettings(options) {
|
|
8764
8952
|
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8765
8953
|
var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
|
|
8766
8954
|
if (!apiKey) {
|
|
8767
8955
|
throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
|
|
8768
8956
|
}
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8957
|
+
var model = normalizeOptionalString(options === null || options === void 0 ? void 0 : options.model) || resolveCodexModel();
|
|
8958
|
+
var fallbackModels = resolveCodexFallbackModels({ fallbackModels: options === null || options === void 0 ? void 0 : options.fallbackModels }, model);
|
|
8959
|
+
return __assign(__assign({ apiKey: apiKey, baseUrl: (serverConfig['OPENAI_BASE_URL'] || process.env.OPENAI_BASE_URL || '').trim() || undefined, model: model }, (fallbackModels.length ? { fallbackModel: fallbackModels[0], fallbackModels: fallbackModels } : {})), { maxRetries: normalizeOptionalNumber(serverConfig['OPENAI_MAX_RETRIES'] || process.env.OPENAI_MAX_RETRIES), retryDelayMs: normalizeOptionalNumber(serverConfig['OPENAI_RETRY_DELAY_MS'] || process.env.OPENAI_RETRY_DELAY_MS) });
|
|
8960
|
+
}
|
|
8961
|
+
function buildAssistantCodexClientCacheKey(config) {
|
|
8962
|
+
var _a, _b;
|
|
8963
|
+
return JSON.stringify({
|
|
8964
|
+
apiKey: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.apiKey),
|
|
8965
|
+
baseUrl: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.baseUrl),
|
|
8966
|
+
model: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.model),
|
|
8967
|
+
fallbackModel: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.fallbackModel),
|
|
8968
|
+
fallbackModels: normalizeCodexModelList(config === null || config === void 0 ? void 0 : config.fallbackModels),
|
|
8969
|
+
maxRetries: (_a = config === null || config === void 0 ? void 0 : config.maxRetries) !== null && _a !== void 0 ? _a : null,
|
|
8970
|
+
retryDelayMs: (_b = config === null || config === void 0 ? void 0 : config.retryDelayMs) !== null && _b !== void 0 ? _b : null
|
|
8971
|
+
});
|
|
8776
8972
|
}
|
|
8777
|
-
function getAssistantCodexClient() {
|
|
8778
|
-
|
|
8779
|
-
|
|
8973
|
+
function getAssistantCodexClient(config) {
|
|
8974
|
+
var resolved = config || resolveCodexSettings();
|
|
8975
|
+
var key = buildAssistantCodexClientCacheKey(resolved);
|
|
8976
|
+
var existing = assistantCodexClientByConfig.get(key);
|
|
8977
|
+
if (existing) {
|
|
8978
|
+
return existing;
|
|
8780
8979
|
}
|
|
8781
|
-
|
|
8980
|
+
var client = new codex_client_1.CodexClient(resolved);
|
|
8981
|
+
assistantCodexClientByConfig.set(key, client);
|
|
8982
|
+
return client;
|
|
8782
8983
|
}
|
|
8783
8984
|
var CodexWorkerBootstrapError = /** @class */ (function (_super) {
|
|
8784
8985
|
__extends(CodexWorkerBootstrapError, _super);
|
|
@@ -8873,14 +9074,14 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
|
|
|
8873
9074
|
case 0:
|
|
8874
9075
|
streamedOptions = applyCodexStreamStatusHandler(runOptions, streamStatusHandler);
|
|
8875
9076
|
if (!!resolveCodexWorkerThreadEnabled()) return [3 /*break*/, 2];
|
|
8876
|
-
codexClient = getAssistantCodexClient();
|
|
9077
|
+
codexClient = getAssistantCodexClient(config);
|
|
8877
9078
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8878
9079
|
case 1: return [2 /*return*/, _a.sent()];
|
|
8879
9080
|
case 2: return [4 /*yield*/, resolveCodexWorkerPath()];
|
|
8880
9081
|
case 3:
|
|
8881
9082
|
workerPath = _a.sent();
|
|
8882
9083
|
if (!!workerPath) return [3 /*break*/, 5];
|
|
8883
|
-
codexClient = getAssistantCodexClient();
|
|
9084
|
+
codexClient = getAssistantCodexClient(config);
|
|
8884
9085
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8885
9086
|
case 4: return [2 /*return*/, _a.sent()];
|
|
8886
9087
|
case 5:
|
|
@@ -8893,7 +9094,7 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
|
|
|
8893
9094
|
throw error_4;
|
|
8894
9095
|
}
|
|
8895
9096
|
console.error('Codex worker bootstrap failed, falling back to in-process run.', error_4);
|
|
8896
|
-
codexClient = getAssistantCodexClient();
|
|
9097
|
+
codexClient = getAssistantCodexClient(config);
|
|
8897
9098
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8898
9099
|
case 8: return [2 /*return*/, _a.sent()];
|
|
8899
9100
|
case 9: return [2 /*return*/];
|
|
@@ -9055,7 +9256,8 @@ function sanitizeCodexRunOptions(options) {
|
|
|
9055
9256
|
timeoutMs: options.timeoutMs,
|
|
9056
9257
|
threadOptions: options.threadOptions,
|
|
9057
9258
|
threadKey: options.threadKey,
|
|
9058
|
-
reuseThread: options.reuseThread
|
|
9259
|
+
reuseThread: options.reuseThread,
|
|
9260
|
+
fallbackModels: options.fallbackModels
|
|
9059
9261
|
};
|
|
9060
9262
|
}
|
|
9061
9263
|
function resolveCodexWorkerPath() {
|
|
@@ -9438,6 +9640,10 @@ function buildAssistantContext(input, userContext) {
|
|
|
9438
9640
|
lines.push(hint);
|
|
9439
9641
|
});
|
|
9440
9642
|
}
|
|
9643
|
+
var recentToolError = normalizeOptionalString(userContext === null || userContext === void 0 ? void 0 : userContext.recentToolError);
|
|
9644
|
+
if (recentToolError) {
|
|
9645
|
+
lines.push("Most recent data-query error: ".concat(recentToolError));
|
|
9646
|
+
}
|
|
9441
9647
|
var mongoDb = normalizeOptionalString((_c = input === null || input === void 0 ? void 0 : input.mongo) === null || _c === void 0 ? void 0 : _c.database);
|
|
9442
9648
|
var mongoDbs = Array.isArray((_d = input === null || input === void 0 ? void 0 : input.mongo) === null || _d === void 0 ? void 0 : _d.databases)
|
|
9443
9649
|
? input.mongo.databases.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
|
|
@@ -9534,6 +9740,34 @@ function buildAssistantFieldHints(message, collectionNames, options) {
|
|
|
9534
9740
|
});
|
|
9535
9741
|
return hints;
|
|
9536
9742
|
}
|
|
9743
|
+
function isAssistantWhyFollowupMessage(message) {
|
|
9744
|
+
var normalized = normalizeOptionalString(message).toLowerCase();
|
|
9745
|
+
if (!normalized) {
|
|
9746
|
+
return false;
|
|
9747
|
+
}
|
|
9748
|
+
return /^(so\s+)?why(?:\s+not)?[.!?]*$/.test(normalized)
|
|
9749
|
+
|| /^(so\s+)?why\b/.test(normalized);
|
|
9750
|
+
}
|
|
9751
|
+
function resolveRecentAssistantToolError(history) {
|
|
9752
|
+
var _a, _b;
|
|
9753
|
+
var entries = Array.isArray(history) ? history : [];
|
|
9754
|
+
for (var i = entries.length - 1; i >= 0; i -= 1) {
|
|
9755
|
+
var entry = entries[i];
|
|
9756
|
+
if ((entry === null || entry === void 0 ? void 0 : entry.role) !== 'assistant') {
|
|
9757
|
+
continue;
|
|
9758
|
+
}
|
|
9759
|
+
var notes = Array.isArray((_b = (_a = entry === null || entry === void 0 ? void 0 : entry.metadata) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.notes)
|
|
9760
|
+
? entry.metadata.debug.notes
|
|
9761
|
+
: [];
|
|
9762
|
+
var matched = notes
|
|
9763
|
+
.map(function (note) { return normalizeOptionalString(note); })
|
|
9764
|
+
.find(function (note) { return note.toLowerCase().startsWith('tool error:'); });
|
|
9765
|
+
if (matched) {
|
|
9766
|
+
return matched.replace(/^tool error:\s*/i, '').trim();
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
return '';
|
|
9770
|
+
}
|
|
9537
9771
|
var cachedClientRouteIndex = null;
|
|
9538
9772
|
function normalizeRouteKey(value) {
|
|
9539
9773
|
var trimmed = normalizeOptionalString(value);
|