@resolveio/server-lib 22.0.13 → 22.0.14
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 +121 -23
- package/methods/ai-terminal.js.map +1 -1
- package/package.json +1 -1
package/methods/ai-terminal.js
CHANGED
|
@@ -373,7 +373,7 @@ var AI_ASSISTANT_TERM_SYNONYMS = [
|
|
|
373
373
|
var AI_ASSISTANT_REPORT_BUILDER_EXPERT_PLAYBOOK = [
|
|
374
374
|
'Report Builder Bridge Expert Playbook (execute in order for every data request):',
|
|
375
375
|
'1) Determine if data is required.',
|
|
376
|
-
'- If user asks for counts, lists, totals, trends, rankings, or "recent/last", run a
|
|
376
|
+
'- If user asks for counts, lists, totals, trends, rankings, or "recent/last", run a data directive before answering.',
|
|
377
377
|
'',
|
|
378
378
|
'Report style mapping (always apply):',
|
|
379
379
|
'- Dated report: any breakdown over time (per day/week/month/quarter/year, trends, time-series comparisons).',
|
|
@@ -388,7 +388,7 @@ var AI_ASSISTANT_REPORT_BUILDER_EXPERT_PLAYBOOK = [
|
|
|
388
388
|
'',
|
|
389
389
|
'3) Enforce permissions and scope in the directive.',
|
|
390
390
|
'- Always include permissionView.',
|
|
391
|
-
'-
|
|
391
|
+
'- Prefer module-specific permissionView routes (for example /invoice/list for invoices). Avoid /report/* routes and only use /report-builder when the user is explicitly asking about report building.',
|
|
392
392
|
'- Assume non-super-admin unless explicitly told otherwise.',
|
|
393
393
|
'- Invoice-like collections require invoice view access.',
|
|
394
394
|
'- Customer portal users must stay in their own customer scope.',
|
|
@@ -492,8 +492,8 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
492
492
|
'- REPORT_BUILDER_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
|
|
493
493
|
'- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
|
|
494
494
|
'- REPORT_BUILDER_AGG: {"collection":"<name>","pipeline":[...],"options":{"allowDiskUse":true,"limit":20},"permissionView":"</route>"}',
|
|
495
|
-
'- For invoice data, set permissionView to an invoice-capable route (ex: /invoice/list
|
|
496
|
-
'- Do not use /report/* routes as permissionView for data directives; use
|
|
495
|
+
'- For invoice data, set permissionView to an invoice-capable route (ex: /invoice/list).',
|
|
496
|
+
'- Do not use /report/* routes as permissionView for data directives; use a module route that matches the collection.',
|
|
497
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.',
|
|
498
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.',
|
|
499
499
|
'- For relative date ranges (last/past/recent), include an upper bound <= $$NOW unless the user specifies a future end date.',
|
|
@@ -3624,7 +3624,7 @@ function buildAssistantToolRequest(directive, payload) {
|
|
|
3624
3624
|
var base = directive.payload && typeof directive.payload === 'object' ? directive.payload : {};
|
|
3625
3625
|
var request = __assign({}, base);
|
|
3626
3626
|
if (!request.permissionView) {
|
|
3627
|
-
request.permissionView =
|
|
3627
|
+
request.permissionView = resolveDefaultAssistantPermissionView(request.collection);
|
|
3628
3628
|
}
|
|
3629
3629
|
request.permissionView = normalizeAssistantPermissionView(request.permissionView, request.collection);
|
|
3630
3630
|
if (!request.id_client) {
|
|
@@ -3638,21 +3638,53 @@ function buildAssistantToolRequest(directive, payload) {
|
|
|
3638
3638
|
}
|
|
3639
3639
|
return request;
|
|
3640
3640
|
}
|
|
3641
|
+
function resolveDefaultAssistantPermissionView(collection) {
|
|
3642
|
+
var normalizedCollection = normalizeOptionalString(collection).toLowerCase();
|
|
3643
|
+
if (!normalizedCollection) {
|
|
3644
|
+
return '/report-builder';
|
|
3645
|
+
}
|
|
3646
|
+
var base = stripVersionSuffix(normalizedCollection.startsWith('report-')
|
|
3647
|
+
? normalizedCollection.slice('report-'.length)
|
|
3648
|
+
: normalizedCollection);
|
|
3649
|
+
if (!base) {
|
|
3650
|
+
return '/report-builder';
|
|
3651
|
+
}
|
|
3652
|
+
if (requiresInvoicePermission(base)) {
|
|
3653
|
+
return '/invoice/list';
|
|
3654
|
+
}
|
|
3655
|
+
if (base.startsWith('sales-tax')) {
|
|
3656
|
+
return '/sales-tax/list';
|
|
3657
|
+
}
|
|
3658
|
+
if (base.startsWith('expense')) {
|
|
3659
|
+
return '/expense/list';
|
|
3660
|
+
}
|
|
3661
|
+
if (base.startsWith('distribution')) {
|
|
3662
|
+
return '/distribution/list';
|
|
3663
|
+
}
|
|
3664
|
+
if (base.startsWith('prospective-client')) {
|
|
3665
|
+
return '/prospective-client/list';
|
|
3666
|
+
}
|
|
3667
|
+
if (base.startsWith('client')) {
|
|
3668
|
+
return '/client/list';
|
|
3669
|
+
}
|
|
3670
|
+
if (base.startsWith('employee')) {
|
|
3671
|
+
return '/employee/list';
|
|
3672
|
+
}
|
|
3673
|
+
return '/report-builder';
|
|
3674
|
+
}
|
|
3641
3675
|
function normalizeAssistantPermissionView(permissionView, collection) {
|
|
3642
3676
|
var normalizedPermission = normalizeOptionalString(permissionView);
|
|
3643
3677
|
var normalizedCollection = normalizeOptionalString(collection);
|
|
3644
3678
|
var loweredPermission = normalizedPermission.toLowerCase();
|
|
3679
|
+
var fallbackPermission = resolveDefaultAssistantPermissionView(normalizedCollection);
|
|
3645
3680
|
if (!normalizedPermission) {
|
|
3646
|
-
return
|
|
3681
|
+
return fallbackPermission;
|
|
3647
3682
|
}
|
|
3648
3683
|
if (loweredPermission === '/report-builder' || loweredPermission.startsWith('/report-builder/')) {
|
|
3649
|
-
return
|
|
3684
|
+
return fallbackPermission;
|
|
3650
3685
|
}
|
|
3651
3686
|
if (loweredPermission === '/report' || loweredPermission.startsWith('/report/')) {
|
|
3652
|
-
|
|
3653
|
-
return '/invoice/list';
|
|
3654
|
-
}
|
|
3655
|
-
return '/report-builder';
|
|
3687
|
+
return fallbackPermission;
|
|
3656
3688
|
}
|
|
3657
3689
|
return normalizedPermission;
|
|
3658
3690
|
}
|
|
@@ -4033,14 +4065,13 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
4033
4065
|
var _a, _b;
|
|
4034
4066
|
var rawMessage = normalizeOptionalString(error === null || error === void 0 ? void 0 : error.message) || 'Unable to access data.';
|
|
4035
4067
|
var normalized = rawMessage.toLowerCase();
|
|
4036
|
-
var
|
|
4037
|
-
|
|
4038
|
-
var collection = normalizeOptionalString(request === null || request === void 0 ? void 0 : request.collection) || normalizeOptionalString((_b = directive.payload) === null || _b === void 0 ? void 0 : _b.collection);
|
|
4068
|
+
var collection = normalizeOptionalString(request === null || request === void 0 ? void 0 : request.collection) || normalizeOptionalString((_a = directive.payload) === null || _a === void 0 ? void 0 : _a.collection);
|
|
4069
|
+
var routeHint = resolveAssistantErrorRouteHint(normalizeOptionalString(request === null || request === void 0 ? void 0 : request.permissionView) || normalizeOptionalString((_b = directive.payload) === null || _b === void 0 ? void 0 : _b.permissionView), collection);
|
|
4039
4070
|
var routeLine = routeHint
|
|
4040
4071
|
? "Open ".concat(routeHint, " in the app to view this data or request access.")
|
|
4041
|
-
: '
|
|
4072
|
+
: 'Request access to the related module in the app.';
|
|
4042
4073
|
if (!routeHint && collection && requiresInvoicePermission(collection)) {
|
|
4043
|
-
routeLine = 'Open /invoice/list
|
|
4074
|
+
routeLine = 'Open /invoice/list in the app to view this data or request access.';
|
|
4044
4075
|
}
|
|
4045
4076
|
if (normalized.includes('permission scope required')) {
|
|
4046
4077
|
return "I need a permission scope to access that data. ".concat(routeLine);
|
|
@@ -4057,14 +4088,30 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
4057
4088
|
if (normalized.includes('undefined variable') && normalized.includes('now_minus')) {
|
|
4058
4089
|
return "The query used an unsupported relative date token. Please retry; the assistant now normalizes relative dates automatically. ".concat(routeLine);
|
|
4059
4090
|
}
|
|
4091
|
+
if (normalized.includes('invalid character for a variable name') && (normalized.includes('now-') || normalized.includes('now+'))) {
|
|
4092
|
+
return "The query used an unsupported relative date token. Please retry; the assistant now normalizes relative dates automatically. ".concat(routeLine);
|
|
4093
|
+
}
|
|
4060
4094
|
if (normalized.includes('report builder bridge') && normalized.includes('not configured')) {
|
|
4061
|
-
return "That dataset is not configured for
|
|
4095
|
+
return "That dataset is not configured for assistant data access yet. ".concat(routeLine);
|
|
4062
4096
|
}
|
|
4063
4097
|
if (normalized.includes('collection is required')) {
|
|
4064
4098
|
return 'I need a valid collection to read from. Please specify which screen or dataset you want.';
|
|
4065
4099
|
}
|
|
4066
4100
|
return "I couldn't access the requested data. ".concat(routeLine);
|
|
4067
4101
|
}
|
|
4102
|
+
function resolveAssistantErrorRouteHint(routeHint, collection) {
|
|
4103
|
+
var normalizedHint = normalizeOptionalString(routeHint);
|
|
4104
|
+
if (!normalizedHint) {
|
|
4105
|
+
var fallback = resolveDefaultAssistantPermissionView(collection);
|
|
4106
|
+
return fallback.startsWith('/report-builder') ? '' : fallback;
|
|
4107
|
+
}
|
|
4108
|
+
var loweredHint = normalizedHint.toLowerCase();
|
|
4109
|
+
if (loweredHint.startsWith('/report-builder') || loweredHint === '/report' || loweredHint.startsWith('/report/')) {
|
|
4110
|
+
var fallback = resolveDefaultAssistantPermissionView(collection);
|
|
4111
|
+
return fallback.startsWith('/report-builder') ? '' : fallback;
|
|
4112
|
+
}
|
|
4113
|
+
return normalizedHint;
|
|
4114
|
+
}
|
|
4068
4115
|
function deriveAssistantStreamStatus(event) {
|
|
4069
4116
|
var _a;
|
|
4070
4117
|
if (!event || !event.type) {
|
|
@@ -5599,8 +5646,25 @@ function resolveAssistantNumericValue(value) {
|
|
|
5599
5646
|
function isAssistantPercentColumn(column) {
|
|
5600
5647
|
return /(percent|pct|percentage|ratio|rate)\b/.test(column);
|
|
5601
5648
|
}
|
|
5649
|
+
var ASSISTANT_NON_CURRENCY_COLUMN_PATTERN = /\b(invoice\s*number|count|qty|quantity|index|rank|sequence|seq|id|code|ticket|number)\b/;
|
|
5650
|
+
var ASSISTANT_CURRENCY_HINT_PATTERN = /\b(amount|price|cost|balance|fee|revenue|tax|billing|charge|payment|profit|margin|due)\b/;
|
|
5651
|
+
var ASSISTANT_MONEY_TOTAL_PATTERN = /\b(sub\s*total|subtotal|grand\s*total|paid\s*total)\b/;
|
|
5652
|
+
var ASSISTANT_TOTAL_WITH_MONEY_HINT_PATTERN = /\btotal\b.*\b(amount|revenue|sales|tax|price|cost|balance|paid|due|charge|billing|profit|margin)\b/;
|
|
5602
5653
|
function isAssistantCurrencyColumn(column) {
|
|
5603
|
-
|
|
5654
|
+
var normalized = String(column || '').toLowerCase().replace(/[_-]+/g, ' ').trim();
|
|
5655
|
+
if (!normalized) {
|
|
5656
|
+
return false;
|
|
5657
|
+
}
|
|
5658
|
+
var hasMoneyHint = ASSISTANT_CURRENCY_HINT_PATTERN.test(normalized)
|
|
5659
|
+
|| ASSISTANT_MONEY_TOTAL_PATTERN.test(normalized)
|
|
5660
|
+
|| ASSISTANT_TOTAL_WITH_MONEY_HINT_PATTERN.test(normalized);
|
|
5661
|
+
if (ASSISTANT_NON_CURRENCY_COLUMN_PATTERN.test(normalized) && !hasMoneyHint) {
|
|
5662
|
+
return false;
|
|
5663
|
+
}
|
|
5664
|
+
if (/\btotal\b/.test(normalized) && !hasMoneyHint) {
|
|
5665
|
+
return false;
|
|
5666
|
+
}
|
|
5667
|
+
return hasMoneyHint;
|
|
5604
5668
|
}
|
|
5605
5669
|
function isAssistantDateColumn(column) {
|
|
5606
5670
|
return /(date|time|created|updated|timestamp|at)\b/.test(column);
|
|
@@ -5914,6 +5978,7 @@ function sanitizeAssistantProjection(projection) {
|
|
|
5914
5978
|
}
|
|
5915
5979
|
var AGG_MATCH_EXPR_OPERATORS = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte']);
|
|
5916
5980
|
var ASSISTANT_NOW_RELATIVE_PATTERN = /^\$\$NOW_(MINUS|PLUS)_([0-9]+)_(MINUTES?|HOURS?|DAYS?|WEEKS?|MONTHS?|YEARS?)$/i;
|
|
5981
|
+
var ASSISTANT_NOW_RELATIVE_COMPACT_PATTERN = /^\$\$NOW([+-])([0-9]+)\s*(MINUTES?|MINS?|MIN|HOURS?|HRS?|HR|DAYS?|WEEKS?|WKS?|WK|MONTHS?|MOS?|MO|M|YEARS?|YRS?|YR|Y)$/i;
|
|
5917
5982
|
function normalizeAssistantTimeUnit(raw) {
|
|
5918
5983
|
var normalized = String(raw || '').toLowerCase();
|
|
5919
5984
|
if (normalized.startsWith('minute')) {
|
|
@@ -5933,21 +5998,54 @@ function normalizeAssistantTimeUnit(raw) {
|
|
|
5933
5998
|
}
|
|
5934
5999
|
return 'year';
|
|
5935
6000
|
}
|
|
6001
|
+
function normalizeAssistantCompactTimeUnit(raw) {
|
|
6002
|
+
var normalized = String(raw || '').toLowerCase();
|
|
6003
|
+
if (normalized === 'm' || normalized === 'mo' || normalized === 'mos' || normalized.startsWith('month')) {
|
|
6004
|
+
return 'month';
|
|
6005
|
+
}
|
|
6006
|
+
if (normalized === 'min' || normalized === 'mins' || normalized.startsWith('minute')) {
|
|
6007
|
+
return 'minute';
|
|
6008
|
+
}
|
|
6009
|
+
if (normalized === 'h' || normalized === 'hr' || normalized === 'hrs' || normalized.startsWith('hour')) {
|
|
6010
|
+
return 'hour';
|
|
6011
|
+
}
|
|
6012
|
+
if (normalized === 'd' || normalized.startsWith('day')) {
|
|
6013
|
+
return 'day';
|
|
6014
|
+
}
|
|
6015
|
+
if (normalized === 'w' || normalized === 'wk' || normalized === 'wks' || normalized.startsWith('week')) {
|
|
6016
|
+
return 'week';
|
|
6017
|
+
}
|
|
6018
|
+
return 'year';
|
|
6019
|
+
}
|
|
5936
6020
|
function parseAssistantNowRelativeToken(value) {
|
|
5937
6021
|
var trimmed = normalizeOptionalString(value);
|
|
5938
6022
|
if (!trimmed) {
|
|
5939
6023
|
return null;
|
|
5940
6024
|
}
|
|
5941
|
-
var
|
|
5942
|
-
if (
|
|
6025
|
+
var expandedMatch = trimmed.match(ASSISTANT_NOW_RELATIVE_PATTERN);
|
|
6026
|
+
if (expandedMatch) {
|
|
6027
|
+
var direction_1 = String(expandedMatch[1] || '').toUpperCase() === 'PLUS' ? 'PLUS' : 'MINUS';
|
|
6028
|
+
var amount_1 = Number(expandedMatch[2]);
|
|
6029
|
+
if (!Number.isFinite(amount_1) || amount_1 < 0) {
|
|
6030
|
+
return null;
|
|
6031
|
+
}
|
|
6032
|
+
var unit_1 = normalizeAssistantTimeUnit(expandedMatch[3] || '');
|
|
6033
|
+
return {
|
|
6034
|
+
operator: direction_1 === 'PLUS' ? '$dateAdd' : '$dateSubtract',
|
|
6035
|
+
amount: amount_1,
|
|
6036
|
+
unit: unit_1
|
|
6037
|
+
};
|
|
6038
|
+
}
|
|
6039
|
+
var compactMatch = trimmed.match(ASSISTANT_NOW_RELATIVE_COMPACT_PATTERN);
|
|
6040
|
+
if (!compactMatch) {
|
|
5943
6041
|
return null;
|
|
5944
6042
|
}
|
|
5945
|
-
var direction =
|
|
5946
|
-
var amount = Number(
|
|
6043
|
+
var direction = compactMatch[1] === '+' ? 'PLUS' : 'MINUS';
|
|
6044
|
+
var amount = Number(compactMatch[2]);
|
|
5947
6045
|
if (!Number.isFinite(amount) || amount < 0) {
|
|
5948
6046
|
return null;
|
|
5949
6047
|
}
|
|
5950
|
-
var unit =
|
|
6048
|
+
var unit = normalizeAssistantCompactTimeUnit(compactMatch[3] || '');
|
|
5951
6049
|
return {
|
|
5952
6050
|
operator: direction === 'PLUS' ? '$dateAdd' : '$dateSubtract',
|
|
5953
6051
|
amount: amount,
|