@resolveio/server-lib 22.0.9 → 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 +850 -94
- 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;
|
|
@@ -166,6 +167,9 @@ var AI_ASSISTANT_PLANNER_MAX_ROUTES = 200;
|
|
|
166
167
|
var AI_ASSISTANT_PLANNER_DEBUG_MAX_CHARS = 2000;
|
|
167
168
|
var AI_ASSISTANT_LOCALE = 'en-US';
|
|
168
169
|
var AI_ASSISTANT_CURRENCY_CODE = 'USD';
|
|
170
|
+
var AI_ASSISTANT_USD_CURRENCY_TEXT_PATTERN = /\b(?:USD|US\$)(?:\s| | |[\u00A0\u202F\u2007])*\$?\s*([-+]?[0-9][0-9,]*(?:\.[0-9]+)?)/gi;
|
|
171
|
+
var AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD = 0.15;
|
|
172
|
+
var AI_ASSISTANT_REVENUE_VERIFY_PAID_GRAND_GAP_WARN_THRESHOLD = 0.10;
|
|
169
173
|
var AI_ASSISTANT_PROGRESS_TICKS = [
|
|
170
174
|
'Grabbing Data',
|
|
171
175
|
'Drafting response'
|
|
@@ -378,12 +382,13 @@ var AI_ASSISTANT_REPORT_BUILDER_EXPERT_PLAYBOOK = [
|
|
|
378
382
|
'',
|
|
379
383
|
'2) Resolve the target dataset safely.',
|
|
380
384
|
'- Map user wording to internal collection names using routes, collection hints, field hints, and synonym expansion.',
|
|
381
|
-
'- Prefer report-* collections when permissionView is under /report.',
|
|
385
|
+
'- Prefer report-* collections when permissionView is under /report-builder.',
|
|
382
386
|
'- Never use *.versions unless user explicitly requests bug-history/version investigation.',
|
|
383
387
|
'- Never invent collection names or fields.',
|
|
384
388
|
'',
|
|
385
389
|
'3) Enforce permissions and scope in the directive.',
|
|
386
390
|
'- Always include permissionView.',
|
|
391
|
+
'- Use /report-builder as the default permissionView for data directives; avoid /report/* routes.',
|
|
387
392
|
'- Assume non-super-admin unless explicitly told otherwise.',
|
|
388
393
|
'- Invoice-like collections require invoice view access.',
|
|
389
394
|
'- Customer portal users must stay in their own customer scope.',
|
|
@@ -432,7 +437,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
432
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.',
|
|
433
438
|
'- Never use *.versions collections for normal requests. Only use a .versions collection when explicitly investigating a bug by checking the last ~5 updates.',
|
|
434
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.',
|
|
435
|
-
'- If permissionView starts with /report
|
|
440
|
+
'- If permissionView starts with /report-builder, prefer the report-* collection when both report and base collections exist.',
|
|
436
441
|
'- Map user wording to internal collections/fields yourself. Do not ask for property names unless required to run a query.',
|
|
437
442
|
'- Use term hints from context (synonym expansions) when mapping user language to collections.',
|
|
438
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.',
|
|
@@ -487,8 +492,10 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
|
487
492
|
'- REPORT_BUILDER_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
|
|
488
493
|
'- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
|
|
489
494
|
'- REPORT_BUILDER_AGG: {"collection":"<name>","pipeline":[...],"options":{"allowDiskUse":true,"limit":20},"permissionView":"</route>"}',
|
|
490
|
-
'- 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.',
|
|
491
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
|
+
'- 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.',
|
|
492
499
|
'- For relative date ranges (last/past/recent), include an upper bound <= $$NOW unless the user specifies a future end date.',
|
|
493
500
|
'- Keep queries minimal, read-only, and avoid user/credential data unless the user is a super admin.',
|
|
494
501
|
'- Assume you are not a super admin unless explicitly told otherwise.',
|
|
@@ -528,7 +535,7 @@ var AI_ASSISTANT_PLANNER_SYSTEM_PROMPT = [
|
|
|
528
535
|
' - Never propose querying blocked/sensitive collections if the user lacks permission.',
|
|
529
536
|
'',
|
|
530
537
|
'4) PERMISSION MATCHING:',
|
|
531
|
-
' - Do NOT hardcode invoice access to "/report
|
|
538
|
+
' - Do NOT hardcode invoice access to "/report-builder/*".',
|
|
532
539
|
' - For invoice-related data or navigation, permission is satisfied if ANY user view contains "invoice" case-insensitive.',
|
|
533
540
|
' (General rule: for an entity token X, permission is satisfied if any view contains X case-insensitive.)',
|
|
534
541
|
' - If permission checks are ambiguous, choose the safest restriction and explain.',
|
|
@@ -663,7 +670,7 @@ var AI_FORM_PATCH_SYSTEM_PROMPT = [
|
|
|
663
670
|
'- Use ISO 8601 for dates and true/false for booleans.',
|
|
664
671
|
'- Use medium reasoning effort.'
|
|
665
672
|
].join('\n');
|
|
666
|
-
var
|
|
673
|
+
var assistantCodexClientByConfig = new Map();
|
|
667
674
|
var assistantCodexRunQueue = [];
|
|
668
675
|
var assistantCodexRunDraining = false;
|
|
669
676
|
/* eslint-enable no-unused-vars */
|
|
@@ -1316,7 +1323,7 @@ function executeAiFormPatch(payload, context) {
|
|
|
1316
1323
|
}
|
|
1317
1324
|
function executeAiAssistantCodexRun(payload, context) {
|
|
1318
1325
|
return __awaiter(this, void 0, void 0, function () {
|
|
1319
|
-
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;
|
|
1320
1327
|
var _this = this;
|
|
1321
1328
|
var _b, _c;
|
|
1322
1329
|
return __generator(this, function (_d) {
|
|
@@ -1332,6 +1339,8 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1332
1339
|
}
|
|
1333
1340
|
aiWorkerDebug = isAiWorkerDebugEnabled();
|
|
1334
1341
|
requestId = normalizeOptionalString(input.request_id);
|
|
1342
|
+
codexModel = resolveCodexModel(input.config);
|
|
1343
|
+
codexFallbackModels = resolveCodexFallbackModels(input.config, codexModel);
|
|
1335
1344
|
guardrail = evaluateAssistantGuardrails(message);
|
|
1336
1345
|
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
|
|
1337
1346
|
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
@@ -1411,6 +1420,9 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1411
1420
|
historyLines.push("".concat(role, ": ").concat(content));
|
|
1412
1421
|
}
|
|
1413
1422
|
});
|
|
1423
|
+
recentToolError = isAssistantWhyFollowupMessage(message)
|
|
1424
|
+
? resolveRecentAssistantToolError(history)
|
|
1425
|
+
: '';
|
|
1414
1426
|
userDoc = {
|
|
1415
1427
|
id_conversation: conversation._id,
|
|
1416
1428
|
role: 'user',
|
|
@@ -1425,7 +1437,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1425
1437
|
id_conversation: conversation._id,
|
|
1426
1438
|
role: 'assistant',
|
|
1427
1439
|
content: AI_ASSISTANT_PROGRESS_PLACEHOLDER,
|
|
1428
|
-
metadata: __assign(__assign({ model:
|
|
1440
|
+
metadata: __assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), { pending: true, progress: initialProgress }),
|
|
1429
1441
|
createdAt: now,
|
|
1430
1442
|
updatedAt: now
|
|
1431
1443
|
};
|
|
@@ -1560,16 +1572,22 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1560
1572
|
customerId: customerId,
|
|
1561
1573
|
collectionHints: collectionHints,
|
|
1562
1574
|
termHints: termHints,
|
|
1563
|
-
fieldHints: fieldHints
|
|
1575
|
+
fieldHints: fieldHints,
|
|
1576
|
+
recentToolError: recentToolError
|
|
1564
1577
|
});
|
|
1565
1578
|
prompt_1 = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
|
|
1566
1579
|
return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
|
|
1567
1580
|
case 6:
|
|
1568
1581
|
workspaceRoot = _x.sent();
|
|
1569
|
-
codexConfig = resolveCodexSettings(
|
|
1582
|
+
codexConfig = resolveCodexSettings({
|
|
1583
|
+
model: codexModel,
|
|
1584
|
+
fallbackModels: codexFallbackModels
|
|
1585
|
+
});
|
|
1570
1586
|
runOptions = {
|
|
1571
1587
|
timeoutMs: resolveCodexTimeoutMs(),
|
|
1588
|
+
fallbackModels: codexFallbackModels,
|
|
1572
1589
|
threadOptions: {
|
|
1590
|
+
model: codexModel,
|
|
1573
1591
|
workingDirectory: workspaceRoot,
|
|
1574
1592
|
sandboxMode: 'read-only',
|
|
1575
1593
|
skipGitRepoCheck: true,
|
|
@@ -1799,6 +1817,8 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1799
1817
|
if (!assistantContent) {
|
|
1800
1818
|
assistantContent = buildAssistantCodexErrorMessage(null);
|
|
1801
1819
|
}
|
|
1820
|
+
assistantContent = applyAssistantVerificationNotes(assistantContent, toolResult);
|
|
1821
|
+
assistantContent = normalizeAssistantCurrencyText(assistantContent);
|
|
1802
1822
|
if (aiWorkerDebug) {
|
|
1803
1823
|
finishedAt = Date.now();
|
|
1804
1824
|
console.log(new Date(), '[AI Worker Debug] codex run complete', {
|
|
@@ -1868,7 +1888,7 @@ function executeAiAssistantCodexRun(payload, context) {
|
|
|
1868
1888
|
}
|
|
1869
1889
|
});
|
|
1870
1890
|
}
|
|
1871
|
-
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 } : {}));
|
|
1872
1892
|
finalAssistantDoc = __assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata, updatedAt: finalNow });
|
|
1873
1893
|
if (!assistantMessageId) return [3 /*break*/, 39];
|
|
1874
1894
|
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: assistantMessageId }, {
|
|
@@ -2398,7 +2418,7 @@ function executeAiAssistantMongoRead(payload, context) {
|
|
|
2398
2418
|
}
|
|
2399
2419
|
function executeAiAssistantMongoAggregate(payload, context) {
|
|
2400
2420
|
return __awaiter(this, void 0, void 0, function () {
|
|
2401
|
-
var input, rawCollection, dbName, db, collectionResolution, collection, bridgeCollection, schemaFields, _a, user, isSuperAdmin, customerId, fallbackMeta, baseQuery, stripped, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, sanitizedPipeline, strippedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, dateField, aggregateOptions, documents, executedPipeline, probeDocs, fallback, fallbackPipeline, fallbackDocs, createdFallback, createdPipeline, createdDocs, expanded, expandedDocs, completionFallback, fallbackPipeline, fallbackDocs, completionExprFallback, fallbackPipeline, fallbackDocs, unwindFallback, shouldUnwind, _c, _d, fallbackPipeline, fallbackDocs, nameFallback, fallbackPipeline, fallbackDocs, _e, _loop_1, i, state_1, matchFields_1, _f, aliases, rewrittenPipeline, fallbackDocs, _loop_2, i, state_2, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, matchStages, diagnostics, combinedMatch, nameFields, dateFields, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, sanitizedDocuments, includeIds, displayDocs, idLookupDisplay, display;
|
|
2421
|
+
var input, rawCollection, dbName, db, collectionResolution, collection, bridgeCollection, schemaFields, _a, user, isSuperAdmin, customerId, fallbackMeta, baseQuery, stripped, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, sanitizedPipeline, strippedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, dateField, aggregateOptions, documents, executedPipeline, probeDocs, fallback, fallbackPipeline, fallbackDocs, createdFallback, createdPipeline, createdDocs, expanded, expandedDocs, completionFallback, fallbackPipeline, fallbackDocs, completionExprFallback, fallbackPipeline, fallbackDocs, unwindFallback, shouldUnwind, _c, _d, fallbackPipeline, fallbackDocs, nameFallback, fallbackPipeline, fallbackDocs, _e, _loop_1, i, state_1, matchFields_1, _f, aliases, rewrittenPipeline, fallbackDocs, _loop_2, i, state_2, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, matchStages, diagnostics, combinedMatch, nameFields, dateFields, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, verification, sanitizedDocuments, includeIds, displayDocs, idLookupDisplay, display;
|
|
2402
2422
|
var _o, _p;
|
|
2403
2423
|
return __generator(this, function (_q) {
|
|
2404
2424
|
switch (_q.label) {
|
|
@@ -2975,7 +2995,15 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
2975
2995
|
case 60:
|
|
2976
2996
|
fallbackMeta.zeroDiagnostics = diagnostics;
|
|
2977
2997
|
_q.label = 61;
|
|
2978
|
-
case 61:
|
|
2998
|
+
case 61: return [4 /*yield*/, verifyAssistantAggregateReliability({
|
|
2999
|
+
db: db,
|
|
3000
|
+
collection: collection,
|
|
3001
|
+
pipeline: executedPipeline,
|
|
3002
|
+
documents: documents,
|
|
3003
|
+
aggregateOptions: aggregateOptions
|
|
3004
|
+
})];
|
|
3005
|
+
case 62:
|
|
3006
|
+
verification = _q.sent();
|
|
2979
3007
|
sanitizedDocuments = isSuperAdmin
|
|
2980
3008
|
? documents
|
|
2981
3009
|
: documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
|
|
@@ -2990,7 +3018,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
2990
3018
|
idCustomer: customerId,
|
|
2991
3019
|
isSuperAdmin: isSuperAdmin
|
|
2992
3020
|
})];
|
|
2993
|
-
case
|
|
3021
|
+
case 63:
|
|
2994
3022
|
idLookupDisplay = _q.sent();
|
|
2995
3023
|
if (idLookupDisplay === null || idLookupDisplay === void 0 ? void 0 : idLookupDisplay.docs) {
|
|
2996
3024
|
displayDocs = idLookupDisplay.docs;
|
|
@@ -3004,27 +3032,482 @@ function executeAiAssistantMongoAggregate(payload, context) {
|
|
|
3004
3032
|
maxRows: normalizedOptions.limit || sanitizedDocuments.length,
|
|
3005
3033
|
includeGroupFromId: true
|
|
3006
3034
|
});
|
|
3007
|
-
return [2 /*return*/, __assign({ documents: sanitizedDocuments, display: display }, (isSuperAdmin ? {
|
|
3008
|
-
debug: {
|
|
3009
|
-
collection: collection,
|
|
3010
|
-
collectionRequested: rawCollection,
|
|
3011
|
-
collectionResolved: collection,
|
|
3012
|
-
collectionMatched: collectionResolution.matched,
|
|
3013
|
-
collectionCandidates: collectionResolution.candidates,
|
|
3014
|
-
collectionScore: collectionResolution.score,
|
|
3015
|
-
bridge: 'report-builder',
|
|
3016
|
-
database: dbName,
|
|
3017
|
-
query: scopedQuery,
|
|
3018
|
-
options: normalizedOptions.aggregateOptions,
|
|
3019
|
-
originalPipeline: limitedPipeline,
|
|
3020
|
-
executedPipeline: executedPipeline,
|
|
3021
|
-
fallbacks: fallbackMeta
|
|
3022
|
-
}
|
|
3035
|
+
return [2 /*return*/, __assign(__assign({ documents: sanitizedDocuments, display: display }, (verification ? { verification: verification } : {})), (isSuperAdmin ? {
|
|
3036
|
+
debug: __assign(__assign({ collection: collection, collectionRequested: rawCollection, collectionResolved: collection, collectionMatched: collectionResolution.matched, collectionCandidates: collectionResolution.candidates, collectionScore: collectionResolution.score, bridge: 'report-builder', database: dbName, query: scopedQuery, options: normalizedOptions.aggregateOptions, originalPipeline: limitedPipeline, executedPipeline: executedPipeline }, (verification ? { verification: verification } : {})), { fallbacks: fallbackMeta })
|
|
3023
3037
|
} : {}))];
|
|
3024
3038
|
}
|
|
3025
3039
|
});
|
|
3026
3040
|
});
|
|
3027
3041
|
}
|
|
3042
|
+
function verifyAssistantAggregateReliability(params) {
|
|
3043
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
3044
|
+
var collection, collectionBase, monthKey, amountKey, baseMap, groupIndex, groupPaths, dateField, mergedMatch, dateFieldsInMatch, baseMatchNoDate, primaryDateCondition, verifyPipeline, verifyDocs, _a, verifyMap, comparedMonths, paidCloserCount, grandCloserCount, sumPaidDiffPct, sumGrandDiffPct, maxPaidDiffPct, maxGrandDiffPct, sumPaidGrandGapPct, highVarianceMonths, checks, warnings, avgPaidDiffPct, avgGrandDiffPct, avgPaidGrandGapPct, baselineMetric, rollingWindow, normalizedMetric, bounds, fullMonthMatch, fullMonthDocs, fullMonthMap, fullMonthDiff, _b, alternateDateField, alternateDateCondition, bounds, alternateMatch, alternateDocs, alternateMap, alternateDiff, _c;
|
|
3045
|
+
var _d, _e;
|
|
3046
|
+
var _f;
|
|
3047
|
+
return __generator(this, function (_g) {
|
|
3048
|
+
switch (_g.label) {
|
|
3049
|
+
case 0:
|
|
3050
|
+
collection = normalizeOptionalString(params.collection).toLowerCase();
|
|
3051
|
+
collectionBase = collection.startsWith('report-') ? collection.slice('report-'.length) : collection;
|
|
3052
|
+
if (collectionBase !== 'invoices') {
|
|
3053
|
+
return [2 /*return*/, null];
|
|
3054
|
+
}
|
|
3055
|
+
monthKey = resolveAssistantMonthlyKey(params.documents);
|
|
3056
|
+
if (!monthKey) {
|
|
3057
|
+
return [2 /*return*/, null];
|
|
3058
|
+
}
|
|
3059
|
+
amountKey = resolveAssistantNumericAmountKey(params.documents, monthKey);
|
|
3060
|
+
if (!amountKey) {
|
|
3061
|
+
return [2 /*return*/, null];
|
|
3062
|
+
}
|
|
3063
|
+
baseMap = mapAssistantRevenueByMonth(params.documents, monthKey, amountKey);
|
|
3064
|
+
if (!baseMap.size) {
|
|
3065
|
+
return [2 /*return*/, null];
|
|
3066
|
+
}
|
|
3067
|
+
groupIndex = findAggregateGroupIndex(params.pipeline || []);
|
|
3068
|
+
if (groupIndex === -1) {
|
|
3069
|
+
return [2 /*return*/, null];
|
|
3070
|
+
}
|
|
3071
|
+
groupPaths = extractGroupFieldPaths(((_f = params.pipeline[groupIndex]) === null || _f === void 0 ? void 0 : _f.$group) || {});
|
|
3072
|
+
dateField = groupPaths.find(function (field) { return /(date|paid|invoice|created|updated|_at)$/i.test(field); })
|
|
3073
|
+
|| groupPaths.find(function (field) { return /(date|paid|invoice|created|updated)/i.test(field); })
|
|
3074
|
+
|| 'date_paid';
|
|
3075
|
+
mergedMatch = mergeAssistantPreGroupMatchStages(params.pipeline || [], groupIndex);
|
|
3076
|
+
dateFieldsInMatch = collectMatchFieldsByCondition(mergedMatch, function (_field, condition) { return isDateCondition(condition); });
|
|
3077
|
+
baseMatchNoDate = dateFieldsInMatch.length ? stripMatchFields(mergedMatch, dateFieldsInMatch) : mergedMatch;
|
|
3078
|
+
primaryDateCondition = findMatchConditionForField(mergedMatch, dateField);
|
|
3079
|
+
verifyPipeline = buildAssistantMonthlyRevenueVerificationPipeline(mergedMatch, dateField);
|
|
3080
|
+
verifyDocs = [];
|
|
3081
|
+
_g.label = 1;
|
|
3082
|
+
case 1:
|
|
3083
|
+
_g.trys.push([1, 3, , 4]);
|
|
3084
|
+
return [4 /*yield*/, params.db.collection(params.collection)
|
|
3085
|
+
.aggregate(verifyPipeline, params.aggregateOptions || {})
|
|
3086
|
+
.toArray()];
|
|
3087
|
+
case 2:
|
|
3088
|
+
verifyDocs = _g.sent();
|
|
3089
|
+
return [3 /*break*/, 4];
|
|
3090
|
+
case 3:
|
|
3091
|
+
_a = _g.sent();
|
|
3092
|
+
return [2 /*return*/, {
|
|
3093
|
+
type: 'invoice_revenue_monthly',
|
|
3094
|
+
checks: [
|
|
3095
|
+
{ name: 'Cross-check query', status: 'warn', details: 'Verification query failed; result not cross-checked.' }
|
|
3096
|
+
],
|
|
3097
|
+
warnings: ['Verification query failed, so this total was not independently cross-checked.'],
|
|
3098
|
+
metrics: {
|
|
3099
|
+
baselineField: amountKey,
|
|
3100
|
+
dateField: dateField
|
|
3101
|
+
}
|
|
3102
|
+
}];
|
|
3103
|
+
case 4:
|
|
3104
|
+
verifyMap = mapAssistantVerificationDocsByMonth(verifyDocs);
|
|
3105
|
+
comparedMonths = 0;
|
|
3106
|
+
paidCloserCount = 0;
|
|
3107
|
+
grandCloserCount = 0;
|
|
3108
|
+
sumPaidDiffPct = 0;
|
|
3109
|
+
sumGrandDiffPct = 0;
|
|
3110
|
+
maxPaidDiffPct = 0;
|
|
3111
|
+
maxGrandDiffPct = 0;
|
|
3112
|
+
sumPaidGrandGapPct = 0;
|
|
3113
|
+
highVarianceMonths = [];
|
|
3114
|
+
baseMap.forEach(function (value, month) {
|
|
3115
|
+
var match = verifyMap.get(month);
|
|
3116
|
+
if (!match) {
|
|
3117
|
+
return;
|
|
3118
|
+
}
|
|
3119
|
+
comparedMonths += 1;
|
|
3120
|
+
var paidDiff = Math.abs(value - match.paid);
|
|
3121
|
+
var grandDiff = Math.abs(value - match.grand);
|
|
3122
|
+
var denom = Math.max(Math.abs(value), 1);
|
|
3123
|
+
var paidPct = paidDiff / denom;
|
|
3124
|
+
var grandPct = grandDiff / denom;
|
|
3125
|
+
sumPaidDiffPct += paidPct;
|
|
3126
|
+
sumGrandDiffPct += grandPct;
|
|
3127
|
+
maxPaidDiffPct = Math.max(maxPaidDiffPct, paidPct);
|
|
3128
|
+
maxGrandDiffPct = Math.max(maxGrandDiffPct, grandPct);
|
|
3129
|
+
if (paidDiff < grandDiff) {
|
|
3130
|
+
paidCloserCount += 1;
|
|
3131
|
+
}
|
|
3132
|
+
else if (grandDiff < paidDiff) {
|
|
3133
|
+
grandCloserCount += 1;
|
|
3134
|
+
}
|
|
3135
|
+
var gapPct = Math.abs(match.paid - match.grand) / Math.max(Math.abs(match.grand), 1);
|
|
3136
|
+
sumPaidGrandGapPct += gapPct;
|
|
3137
|
+
if (Math.min(paidPct, grandPct) >= AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD) {
|
|
3138
|
+
highVarianceMonths.push(month);
|
|
3139
|
+
}
|
|
3140
|
+
});
|
|
3141
|
+
checks = [];
|
|
3142
|
+
warnings = [];
|
|
3143
|
+
avgPaidDiffPct = comparedMonths ? (sumPaidDiffPct / comparedMonths) : 0;
|
|
3144
|
+
avgGrandDiffPct = comparedMonths ? (sumGrandDiffPct / comparedMonths) : 0;
|
|
3145
|
+
avgPaidGrandGapPct = comparedMonths ? (sumPaidGrandGapPct / comparedMonths) : 0;
|
|
3146
|
+
baselineMetric = 'unknown';
|
|
3147
|
+
if (comparedMonths) {
|
|
3148
|
+
if (paidCloserCount > grandCloserCount) {
|
|
3149
|
+
baselineMetric = 'paid_total (date_paid)';
|
|
3150
|
+
}
|
|
3151
|
+
else if (grandCloserCount > paidCloserCount) {
|
|
3152
|
+
baselineMetric = 'grand_total (date_paid)';
|
|
3153
|
+
}
|
|
3154
|
+
else {
|
|
3155
|
+
baselineMetric = 'mixed';
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
if (!comparedMonths) {
|
|
3159
|
+
checks.push({
|
|
3160
|
+
name: 'Cross-check coverage',
|
|
3161
|
+
status: 'warn',
|
|
3162
|
+
details: 'No overlapping month rows were available for verification.'
|
|
3163
|
+
});
|
|
3164
|
+
warnings.push('Could not cross-check this result against alternate invoice total fields for the same months.');
|
|
3165
|
+
}
|
|
3166
|
+
else {
|
|
3167
|
+
checks.push({
|
|
3168
|
+
name: 'Metric alignment',
|
|
3169
|
+
status: baselineMetric === 'mixed' ? 'warn' : 'pass',
|
|
3170
|
+
details: "Result aligns most with ".concat(baselineMetric, ".")
|
|
3171
|
+
});
|
|
3172
|
+
if (baselineMetric === 'mixed') {
|
|
3173
|
+
warnings.push('Revenue appears to mix definitions across months (paid_total vs grand_total).');
|
|
3174
|
+
}
|
|
3175
|
+
checks.push({
|
|
3176
|
+
name: 'Field variance',
|
|
3177
|
+
status: avgPaidGrandGapPct >= AI_ASSISTANT_REVENUE_VERIFY_PAID_GRAND_GAP_WARN_THRESHOLD ? 'warn' : 'pass',
|
|
3178
|
+
details: "Average paid-vs-grand gap: ".concat((0, common_1.round)(avgPaidGrandGapPct * 100, 2), "%.")
|
|
3179
|
+
});
|
|
3180
|
+
if (avgPaidGrandGapPct >= AI_ASSISTANT_REVENUE_VERIFY_PAID_GRAND_GAP_WARN_THRESHOLD) {
|
|
3181
|
+
warnings.push("paid_total and grand_total differ materially for this period (".concat((0, common_1.round)(avgPaidGrandGapPct * 100, 2), "% average gap)."));
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
rollingWindow = detectAssistantRollingMonthWindow(params.pipeline || []);
|
|
3185
|
+
if ((rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.months) && (rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.upperNow)) {
|
|
3186
|
+
checks.push({
|
|
3187
|
+
name: 'Date window shape',
|
|
3188
|
+
status: 'warn',
|
|
3189
|
+
details: "Query uses rolling $$NOW bounds (last ".concat(rollingWindow.months, " months), which can include partial months.")
|
|
3190
|
+
});
|
|
3191
|
+
warnings.push("Date window is rolling (last ".concat(rollingWindow.months, " months to now), so first/current months may be partial."));
|
|
3192
|
+
}
|
|
3193
|
+
else {
|
|
3194
|
+
checks.push({
|
|
3195
|
+
name: 'Date window shape',
|
|
3196
|
+
status: 'pass',
|
|
3197
|
+
details: 'No rolling $$NOW month window pattern detected.'
|
|
3198
|
+
});
|
|
3199
|
+
}
|
|
3200
|
+
normalizedMetric = normalizeAssistantVerificationMetric(baselineMetric);
|
|
3201
|
+
if (!((rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.months) && (rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.upperNow))) return [3 /*break*/, 8];
|
|
3202
|
+
bounds = resolveAssistantRollingWindowBounds(rollingWindow.months);
|
|
3203
|
+
fullMonthMatch = mergeAssistantMatch(baseMatchNoDate, (_d = {},
|
|
3204
|
+
_d[dateField] = {
|
|
3205
|
+
$gte: bounds.startOfWindow,
|
|
3206
|
+
$lt: bounds.startOfCurrentMonth
|
|
3207
|
+
},
|
|
3208
|
+
_d));
|
|
3209
|
+
_g.label = 5;
|
|
3210
|
+
case 5:
|
|
3211
|
+
_g.trys.push([5, 7, , 8]);
|
|
3212
|
+
return [4 /*yield*/, params.db.collection(params.collection)
|
|
3213
|
+
.aggregate(buildAssistantMonthlyRevenueVerificationPipeline(fullMonthMatch, dateField), params.aggregateOptions || {})
|
|
3214
|
+
.toArray()];
|
|
3215
|
+
case 6:
|
|
3216
|
+
fullMonthDocs = _g.sent();
|
|
3217
|
+
fullMonthMap = mapAssistantMetricByMonth(mapAssistantVerificationDocsByMonth(fullMonthDocs), normalizedMetric);
|
|
3218
|
+
fullMonthDiff = compareAssistantMonthlyValueMaps(baseMap, fullMonthMap);
|
|
3219
|
+
checks.push({
|
|
3220
|
+
name: 'Full-month cross-check',
|
|
3221
|
+
status: fullMonthDiff.comparedMonths && fullMonthDiff.avgDiffPct < AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD ? 'pass' : 'warn',
|
|
3222
|
+
details: fullMonthDiff.comparedMonths
|
|
3223
|
+
? "Compared ".concat(fullMonthDiff.comparedMonths, " month(s); avg diff ").concat((0, common_1.round)(fullMonthDiff.avgDiffPct * 100, 2), "%.")
|
|
3224
|
+
: 'No overlapping months for full-month cross-check.'
|
|
3225
|
+
});
|
|
3226
|
+
if (fullMonthDiff.comparedMonths && fullMonthDiff.avgDiffPct >= AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD) {
|
|
3227
|
+
warnings.push("Rolling-window totals differ from full-month totals by ".concat((0, common_1.round)(fullMonthDiff.avgDiffPct * 100, 2), "% on average."));
|
|
3228
|
+
}
|
|
3229
|
+
if (!fullMonthDiff.comparedMonths) {
|
|
3230
|
+
warnings.push('Could not compare rolling-window results against full-month buckets.');
|
|
3231
|
+
}
|
|
3232
|
+
return [3 /*break*/, 8];
|
|
3233
|
+
case 7:
|
|
3234
|
+
_b = _g.sent();
|
|
3235
|
+
checks.push({
|
|
3236
|
+
name: 'Full-month cross-check',
|
|
3237
|
+
status: 'warn',
|
|
3238
|
+
details: 'Full-month verification query failed.'
|
|
3239
|
+
});
|
|
3240
|
+
warnings.push('Full-month verification query failed.');
|
|
3241
|
+
return [3 /*break*/, 8];
|
|
3242
|
+
case 8:
|
|
3243
|
+
alternateDateField = dateField === 'date_paid'
|
|
3244
|
+
? 'date_invoice'
|
|
3245
|
+
: dateField === 'date_invoice'
|
|
3246
|
+
? 'date_paid'
|
|
3247
|
+
: '';
|
|
3248
|
+
if (!alternateDateField) return [3 /*break*/, 12];
|
|
3249
|
+
alternateDateCondition = null;
|
|
3250
|
+
if ((rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.months) && (rollingWindow === null || rollingWindow === void 0 ? void 0 : rollingWindow.upperNow)) {
|
|
3251
|
+
bounds = resolveAssistantRollingWindowBounds(rollingWindow.months);
|
|
3252
|
+
alternateDateCondition = {
|
|
3253
|
+
$gte: bounds.rollingStart,
|
|
3254
|
+
$lte: bounds.now
|
|
3255
|
+
};
|
|
3256
|
+
}
|
|
3257
|
+
else if (primaryDateCondition && typeof primaryDateCondition === 'object') {
|
|
3258
|
+
alternateDateCondition = primaryDateCondition;
|
|
3259
|
+
}
|
|
3260
|
+
if (!alternateDateCondition) return [3 /*break*/, 12];
|
|
3261
|
+
alternateMatch = mergeAssistantMatch(baseMatchNoDate, (_e = {}, _e[alternateDateField] = alternateDateCondition, _e));
|
|
3262
|
+
_g.label = 9;
|
|
3263
|
+
case 9:
|
|
3264
|
+
_g.trys.push([9, 11, , 12]);
|
|
3265
|
+
return [4 /*yield*/, params.db.collection(params.collection)
|
|
3266
|
+
.aggregate(buildAssistantMonthlyRevenueVerificationPipeline(alternateMatch, alternateDateField), params.aggregateOptions || {})
|
|
3267
|
+
.toArray()];
|
|
3268
|
+
case 10:
|
|
3269
|
+
alternateDocs = _g.sent();
|
|
3270
|
+
alternateMap = mapAssistantMetricByMonth(mapAssistantVerificationDocsByMonth(alternateDocs), normalizedMetric);
|
|
3271
|
+
alternateDiff = compareAssistantMonthlyValueMaps(baseMap, alternateMap);
|
|
3272
|
+
checks.push({
|
|
3273
|
+
name: "Alternate date field (".concat(alternateDateField, ")"),
|
|
3274
|
+
status: alternateDiff.comparedMonths && alternateDiff.avgDiffPct < AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD ? 'pass' : 'warn',
|
|
3275
|
+
details: alternateDiff.comparedMonths
|
|
3276
|
+
? "Compared ".concat(alternateDiff.comparedMonths, " month(s); avg diff ").concat((0, common_1.round)(alternateDiff.avgDiffPct * 100, 2), "%.")
|
|
3277
|
+
: 'No overlapping months for alternate date-field cross-check.'
|
|
3278
|
+
});
|
|
3279
|
+
if (alternateDiff.comparedMonths && alternateDiff.avgDiffPct >= AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD) {
|
|
3280
|
+
warnings.push("Switching from ".concat(dateField, " to ").concat(alternateDateField, " changes monthly totals by ").concat((0, common_1.round)(alternateDiff.avgDiffPct * 100, 2), "% on average."));
|
|
3281
|
+
}
|
|
3282
|
+
return [3 /*break*/, 12];
|
|
3283
|
+
case 11:
|
|
3284
|
+
_c = _g.sent();
|
|
3285
|
+
checks.push({
|
|
3286
|
+
name: "Alternate date field (".concat(alternateDateField, ")"),
|
|
3287
|
+
status: 'warn',
|
|
3288
|
+
details: 'Alternate date-field verification query failed.'
|
|
3289
|
+
});
|
|
3290
|
+
return [3 /*break*/, 12];
|
|
3291
|
+
case 12:
|
|
3292
|
+
if (highVarianceMonths.length) {
|
|
3293
|
+
warnings.push("High variance months vs both paid/grand checks: ".concat(highVarianceMonths.join(', '), "."));
|
|
3294
|
+
}
|
|
3295
|
+
return [2 /*return*/, {
|
|
3296
|
+
type: 'invoice_revenue_monthly',
|
|
3297
|
+
checks: checks,
|
|
3298
|
+
warnings: warnings,
|
|
3299
|
+
metrics: {
|
|
3300
|
+
baselineField: amountKey,
|
|
3301
|
+
dateField: dateField,
|
|
3302
|
+
comparedMonths: comparedMonths,
|
|
3303
|
+
avgDiffToPaidPct: (0, common_1.round)(avgPaidDiffPct * 100, 2),
|
|
3304
|
+
avgDiffToGrandPct: (0, common_1.round)(avgGrandDiffPct * 100, 2),
|
|
3305
|
+
maxDiffToPaidPct: (0, common_1.round)(maxPaidDiffPct * 100, 2),
|
|
3306
|
+
maxDiffToGrandPct: (0, common_1.round)(maxGrandDiffPct * 100, 2),
|
|
3307
|
+
avgPaidGrandGapPct: (0, common_1.round)(avgPaidGrandGapPct * 100, 2)
|
|
3308
|
+
}
|
|
3309
|
+
}];
|
|
3310
|
+
}
|
|
3311
|
+
});
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
function resolveAssistantMonthlyKey(documents) {
|
|
3315
|
+
var first = Array.isArray(documents) ? documents.find(function (doc) { return doc && typeof doc === 'object'; }) : null;
|
|
3316
|
+
if (!first) {
|
|
3317
|
+
return '';
|
|
3318
|
+
}
|
|
3319
|
+
return Object.keys(first).find(function (key) {
|
|
3320
|
+
var value = first[key];
|
|
3321
|
+
return typeof value === 'string' && /^\d{4}-\d{2}$/.test(value);
|
|
3322
|
+
}) || '';
|
|
3323
|
+
}
|
|
3324
|
+
function resolveAssistantNumericAmountKey(documents, monthKey) {
|
|
3325
|
+
var first = Array.isArray(documents) ? documents.find(function (doc) { return doc && typeof doc === 'object'; }) : null;
|
|
3326
|
+
if (!first) {
|
|
3327
|
+
return '';
|
|
3328
|
+
}
|
|
3329
|
+
var currencyLike = Object.keys(first).filter(function (key) {
|
|
3330
|
+
if (key === monthKey) {
|
|
3331
|
+
return false;
|
|
3332
|
+
}
|
|
3333
|
+
var value = Number(first[key]);
|
|
3334
|
+
if (!Number.isFinite(value)) {
|
|
3335
|
+
return false;
|
|
3336
|
+
}
|
|
3337
|
+
return /(revenue|amount|total|sales|billing|paid|grand)/i.test(key);
|
|
3338
|
+
});
|
|
3339
|
+
if (currencyLike.length) {
|
|
3340
|
+
return currencyLike[0];
|
|
3341
|
+
}
|
|
3342
|
+
return Object.keys(first).find(function (key) {
|
|
3343
|
+
if (key === monthKey) {
|
|
3344
|
+
return false;
|
|
3345
|
+
}
|
|
3346
|
+
return Number.isFinite(Number(first[key]));
|
|
3347
|
+
}) || '';
|
|
3348
|
+
}
|
|
3349
|
+
function mapAssistantRevenueByMonth(documents, monthKey, valueKey) {
|
|
3350
|
+
var mapped = new Map();
|
|
3351
|
+
(Array.isArray(documents) ? documents : []).forEach(function (doc) {
|
|
3352
|
+
var month = normalizeOptionalString(doc === null || doc === void 0 ? void 0 : doc[monthKey]);
|
|
3353
|
+
if (!month || !/^\d{4}-\d{2}$/.test(month)) {
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
var value = Number(doc === null || doc === void 0 ? void 0 : doc[valueKey]);
|
|
3357
|
+
if (!Number.isFinite(value)) {
|
|
3358
|
+
return;
|
|
3359
|
+
}
|
|
3360
|
+
mapped.set(month, value);
|
|
3361
|
+
});
|
|
3362
|
+
return mapped;
|
|
3363
|
+
}
|
|
3364
|
+
function mergeAssistantPreGroupMatchStages(pipeline, groupIndex) {
|
|
3365
|
+
var matches = [];
|
|
3366
|
+
for (var i = 0; i < groupIndex; i += 1) {
|
|
3367
|
+
var stage = pipeline[i];
|
|
3368
|
+
if (stage && typeof stage === 'object' && stage.$match && typeof stage.$match === 'object') {
|
|
3369
|
+
matches.push(stage.$match);
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
if (!matches.length) {
|
|
3373
|
+
return {};
|
|
3374
|
+
}
|
|
3375
|
+
if (matches.length === 1) {
|
|
3376
|
+
return matches[0];
|
|
3377
|
+
}
|
|
3378
|
+
return { $and: matches };
|
|
3379
|
+
}
|
|
3380
|
+
function detectAssistantRollingMonthWindow(pipeline) {
|
|
3381
|
+
var raw = JSON.stringify(Array.isArray(pipeline) ? pipeline : []);
|
|
3382
|
+
if (!raw) {
|
|
3383
|
+
return null;
|
|
3384
|
+
}
|
|
3385
|
+
var amountMatch = raw.match(/"\$dateSubtract":\{"startDate":"\$\$NOW","unit":"month","amount":([0-9]+)\}/);
|
|
3386
|
+
if (!amountMatch) {
|
|
3387
|
+
return null;
|
|
3388
|
+
}
|
|
3389
|
+
var months = Number(amountMatch[1]);
|
|
3390
|
+
if (!Number.isFinite(months) || months < 1) {
|
|
3391
|
+
return null;
|
|
3392
|
+
}
|
|
3393
|
+
var nowCount = (raw.match(/\$\$NOW/g) || []).length;
|
|
3394
|
+
return {
|
|
3395
|
+
months: months,
|
|
3396
|
+
upperNow: nowCount >= 2
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
function buildAssistantMonthlyRevenueVerificationPipeline(match, dateField) {
|
|
3400
|
+
var pipeline = [];
|
|
3401
|
+
if (match && typeof match === 'object' && Object.keys(match).length) {
|
|
3402
|
+
pipeline.push({ $match: match });
|
|
3403
|
+
}
|
|
3404
|
+
pipeline.push({
|
|
3405
|
+
$group: {
|
|
3406
|
+
_id: {
|
|
3407
|
+
$dateToString: {
|
|
3408
|
+
format: '%Y-%m',
|
|
3409
|
+
date: "$".concat(dateField)
|
|
3410
|
+
}
|
|
3411
|
+
},
|
|
3412
|
+
paid_total_sum: { $sum: { $ifNull: ['$paid_total', 0] } },
|
|
3413
|
+
grand_total_sum: { $sum: { $ifNull: ['$grand_total', 0] } },
|
|
3414
|
+
invoice_count: { $sum: 1 }
|
|
3415
|
+
}
|
|
3416
|
+
}, {
|
|
3417
|
+
$project: {
|
|
3418
|
+
_id: 0,
|
|
3419
|
+
month: '$_id',
|
|
3420
|
+
paid_total_sum: 1,
|
|
3421
|
+
grand_total_sum: 1,
|
|
3422
|
+
invoice_count: 1
|
|
3423
|
+
}
|
|
3424
|
+
}, { $sort: { month: 1 } }, { $limit: 36 });
|
|
3425
|
+
return pipeline;
|
|
3426
|
+
}
|
|
3427
|
+
function mapAssistantVerificationDocsByMonth(docs) {
|
|
3428
|
+
var mapped = new Map();
|
|
3429
|
+
(Array.isArray(docs) ? docs : []).forEach(function (row) {
|
|
3430
|
+
var month = normalizeOptionalString(row === null || row === void 0 ? void 0 : row.month);
|
|
3431
|
+
if (!month || !/^\d{4}-\d{2}$/.test(month)) {
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
var paid = Number(row === null || row === void 0 ? void 0 : row.paid_total_sum);
|
|
3435
|
+
var grand = Number(row === null || row === void 0 ? void 0 : row.grand_total_sum);
|
|
3436
|
+
var count = Number(row === null || row === void 0 ? void 0 : row.invoice_count);
|
|
3437
|
+
mapped.set(month, {
|
|
3438
|
+
paid: Number.isFinite(paid) ? paid : 0,
|
|
3439
|
+
grand: Number.isFinite(grand) ? grand : 0,
|
|
3440
|
+
count: Number.isFinite(count) ? count : 0
|
|
3441
|
+
});
|
|
3442
|
+
});
|
|
3443
|
+
return mapped;
|
|
3444
|
+
}
|
|
3445
|
+
function normalizeAssistantVerificationMetric(value) {
|
|
3446
|
+
var normalized = normalizeOptionalString(value).toLowerCase();
|
|
3447
|
+
if (normalized.startsWith('paid_total')) {
|
|
3448
|
+
return 'paid';
|
|
3449
|
+
}
|
|
3450
|
+
if (normalized.startsWith('grand_total')) {
|
|
3451
|
+
return 'grand';
|
|
3452
|
+
}
|
|
3453
|
+
return 'mixed';
|
|
3454
|
+
}
|
|
3455
|
+
function mapAssistantMetricByMonth(source, metric) {
|
|
3456
|
+
var mapped = new Map();
|
|
3457
|
+
source.forEach(function (value, month) {
|
|
3458
|
+
var next = metric === 'paid'
|
|
3459
|
+
? value.paid
|
|
3460
|
+
: metric === 'grand'
|
|
3461
|
+
? value.grand
|
|
3462
|
+
: value.paid || value.grand;
|
|
3463
|
+
mapped.set(month, Number.isFinite(next) ? next : 0);
|
|
3464
|
+
});
|
|
3465
|
+
return mapped;
|
|
3466
|
+
}
|
|
3467
|
+
function compareAssistantMonthlyValueMaps(base, compare) {
|
|
3468
|
+
var comparedMonths = 0;
|
|
3469
|
+
var sumDiffPct = 0;
|
|
3470
|
+
var maxDiffPct = 0;
|
|
3471
|
+
base.forEach(function (baseValue, month) {
|
|
3472
|
+
var compareValue = compare.get(month);
|
|
3473
|
+
if (typeof compareValue !== 'number') {
|
|
3474
|
+
return;
|
|
3475
|
+
}
|
|
3476
|
+
var diffPct = Math.abs(baseValue - compareValue) / Math.max(Math.abs(baseValue), 1);
|
|
3477
|
+
comparedMonths += 1;
|
|
3478
|
+
sumDiffPct += diffPct;
|
|
3479
|
+
maxDiffPct = Math.max(maxDiffPct, diffPct);
|
|
3480
|
+
});
|
|
3481
|
+
return {
|
|
3482
|
+
comparedMonths: comparedMonths,
|
|
3483
|
+
avgDiffPct: comparedMonths ? (sumDiffPct / comparedMonths) : 0,
|
|
3484
|
+
maxDiffPct: maxDiffPct
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
function mergeAssistantMatch(base, extra) {
|
|
3488
|
+
var baseObj = base && typeof base === 'object' ? base : {};
|
|
3489
|
+
var extraObj = extra && typeof extra === 'object' ? extra : {};
|
|
3490
|
+
if (!Object.keys(baseObj).length) {
|
|
3491
|
+
return extraObj;
|
|
3492
|
+
}
|
|
3493
|
+
if (!Object.keys(extraObj).length) {
|
|
3494
|
+
return baseObj;
|
|
3495
|
+
}
|
|
3496
|
+
return { $and: [baseObj, extraObj] };
|
|
3497
|
+
}
|
|
3498
|
+
function resolveAssistantRollingWindowBounds(months) {
|
|
3499
|
+
var now = new Date();
|
|
3500
|
+
var rollingStart = new Date(now);
|
|
3501
|
+
rollingStart.setUTCMonth(rollingStart.getUTCMonth() - months);
|
|
3502
|
+
var startOfCurrentMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
3503
|
+
var startOfWindow = new Date(Date.UTC(startOfCurrentMonth.getUTCFullYear(), startOfCurrentMonth.getUTCMonth() - months, 1));
|
|
3504
|
+
return {
|
|
3505
|
+
now: now,
|
|
3506
|
+
rollingStart: rollingStart,
|
|
3507
|
+
startOfCurrentMonth: startOfCurrentMonth,
|
|
3508
|
+
startOfWindow: startOfWindow
|
|
3509
|
+
};
|
|
3510
|
+
}
|
|
3028
3511
|
function extractAssistantMongoDirective(content) {
|
|
3029
3512
|
var lines = String(content || '').split('\n');
|
|
3030
3513
|
var directiveIndex = -1;
|
|
@@ -3079,13 +3562,12 @@ function extractAssistantMongoDirective(content) {
|
|
|
3079
3562
|
};
|
|
3080
3563
|
}
|
|
3081
3564
|
function buildAssistantToolRequest(directive, payload) {
|
|
3082
|
-
var _a;
|
|
3083
3565
|
var base = directive.payload && typeof directive.payload === 'object' ? directive.payload : {};
|
|
3084
3566
|
var request = __assign({}, base);
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
request.permissionView = route;
|
|
3567
|
+
if (!request.permissionView) {
|
|
3568
|
+
request.permissionView = '/report-builder';
|
|
3088
3569
|
}
|
|
3570
|
+
request.permissionView = normalizeAssistantPermissionView(request.permissionView, request.collection);
|
|
3089
3571
|
if (!request.id_client) {
|
|
3090
3572
|
var idClient = normalizeOptionalString(payload === null || payload === void 0 ? void 0 : payload.id_client);
|
|
3091
3573
|
if (idClient) {
|
|
@@ -3097,6 +3579,24 @@ function buildAssistantToolRequest(directive, payload) {
|
|
|
3097
3579
|
}
|
|
3098
3580
|
return request;
|
|
3099
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
|
+
}
|
|
3100
3600
|
function buildAssistantToolResultPayload(directive, toolResponse) {
|
|
3101
3601
|
var _a, _b, _c;
|
|
3102
3602
|
var directivePayload = directive.payload || {};
|
|
@@ -3121,6 +3621,9 @@ function buildAssistantToolResultPayload(directive, toolResponse) {
|
|
|
3121
3621
|
|| normalizeOptionalString((_c = toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) === null || _c === void 0 ? void 0 : _c.collection)
|
|
3122
3622
|
|| requestedCollection
|
|
3123
3623
|
|| '';
|
|
3624
|
+
var verification = (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.verification) && typeof toolResponse.verification === 'object'
|
|
3625
|
+
? toolResponse.verification
|
|
3626
|
+
: undefined;
|
|
3124
3627
|
var result = {
|
|
3125
3628
|
type: directive.type === 'aggregate' ? 'mongo_agg' : 'mongo_read',
|
|
3126
3629
|
input: directivePayload,
|
|
@@ -3131,6 +3634,7 @@ function buildAssistantToolResultPayload(directive, toolResponse) {
|
|
|
3131
3634
|
rowCount: rowCount,
|
|
3132
3635
|
columns: trimmedDisplay.columns,
|
|
3133
3636
|
truncated: trimmedDisplay.truncated,
|
|
3637
|
+
verification: verification,
|
|
3134
3638
|
debug: (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) && typeof toolResponse.debug === 'object' ? toolResponse.debug : undefined
|
|
3135
3639
|
}
|
|
3136
3640
|
};
|
|
@@ -3160,6 +3664,26 @@ function buildAssistantToolResultPrompt(result) {
|
|
|
3160
3664
|
else {
|
|
3161
3665
|
lines.push('Preview: (no rows)');
|
|
3162
3666
|
}
|
|
3667
|
+
var verification = result.output.verification;
|
|
3668
|
+
if (verification && typeof verification === 'object') {
|
|
3669
|
+
var checks = Array.isArray(verification.checks) ? verification.checks : [];
|
|
3670
|
+
var warnings = Array.isArray(verification.warnings) ? verification.warnings : [];
|
|
3671
|
+
if (checks.length || warnings.length) {
|
|
3672
|
+
lines.push('Verification:');
|
|
3673
|
+
}
|
|
3674
|
+
checks.slice(0, 4).forEach(function (entry) {
|
|
3675
|
+
var name = normalizeOptionalString(entry === null || entry === void 0 ? void 0 : entry.name) || 'check';
|
|
3676
|
+
var status = normalizeOptionalString(entry === null || entry === void 0 ? void 0 : entry.status).toLowerCase() === 'warn' ? 'warn' : 'pass';
|
|
3677
|
+
var details = normalizeOptionalString(entry === null || entry === void 0 ? void 0 : entry.details);
|
|
3678
|
+
lines.push("- ".concat(name, ": ").concat(status).concat(details ? " (".concat(details, ")") : ''));
|
|
3679
|
+
});
|
|
3680
|
+
warnings.slice(0, 4).forEach(function (warning) {
|
|
3681
|
+
var text = normalizeOptionalString(warning);
|
|
3682
|
+
if (text) {
|
|
3683
|
+
lines.push("- warning: ".concat(text));
|
|
3684
|
+
}
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3163
3687
|
return lines.join('\n');
|
|
3164
3688
|
}
|
|
3165
3689
|
function buildAssistantCodexToolFollowupPrompt(message, attachmentText, historyText, contextText, toolResultText) {
|
|
@@ -3168,7 +3692,7 @@ function buildAssistantCodexToolFollowupPrompt(message, attachmentText, historyT
|
|
|
3168
3692
|
var trimmedHistory = normalizeOptionalString(historyText);
|
|
3169
3693
|
var historyBlock = trimmedHistory ? "\n\nConversation so far:\n".concat(trimmedHistory) : '';
|
|
3170
3694
|
var toolBlock = toolResultText ? "\n\nTool Result:\n".concat(toolResultText) : '';
|
|
3171
|
-
var instruction = '\n\nInstruction:\nNow answer the user. Do NOT output another REPORT_BUILDER_* directive. Output plain Markdown. Summarize first, then include a Markdown table.';
|
|
3695
|
+
var instruction = '\n\nInstruction:\nNow answer the user. Do NOT output another REPORT_BUILDER_* directive. Output plain Markdown. Summarize first, then include a Markdown table. If the Tool Result includes Verification warnings, explicitly include them and call out the metric/date basis used.';
|
|
3172
3696
|
return "System:\n".concat(AI_ASSISTANT_SYSTEM_PROMPT).concat(contextBlock).concat(historyBlock, "\n\nUser:\n").concat(message).concat(attachmentText || '').concat(toolBlock).concat(instruction).trim();
|
|
3173
3697
|
}
|
|
3174
3698
|
function buildAssistantToolFallbackResponse(result) {
|
|
@@ -3187,6 +3711,27 @@ function buildAssistantToolFallbackResponse(result) {
|
|
|
3187
3711
|
}
|
|
3188
3712
|
return lines.join('\n').trim();
|
|
3189
3713
|
}
|
|
3714
|
+
function applyAssistantVerificationNotes(value, toolResult) {
|
|
3715
|
+
var _a, _b, _c, _d;
|
|
3716
|
+
var content = normalizeOptionalString(value);
|
|
3717
|
+
var warnings = Array.isArray((_b = (_a = toolResult === null || toolResult === void 0 ? void 0 : toolResult.output) === null || _a === void 0 ? void 0 : _a.verification) === null || _b === void 0 ? void 0 : _b.warnings)
|
|
3718
|
+
? (_d = (_c = toolResult === null || toolResult === void 0 ? void 0 : toolResult.output) === null || _c === void 0 ? void 0 : _c.verification) === null || _d === void 0 ? void 0 : _d.warnings.map(function (entry) { return normalizeOptionalString(entry); }).filter(Boolean)
|
|
3719
|
+
: [];
|
|
3720
|
+
if (!warnings.length) {
|
|
3721
|
+
return content || value || '';
|
|
3722
|
+
}
|
|
3723
|
+
var normalizedLower = String(content || '').toLowerCase();
|
|
3724
|
+
var missing = warnings.filter(function (warning) { return !normalizedLower.includes(String(warning).toLowerCase()); });
|
|
3725
|
+
if (!missing.length) {
|
|
3726
|
+
return content || value || '';
|
|
3727
|
+
}
|
|
3728
|
+
var noteLines = ['Verification notes:'];
|
|
3729
|
+
missing.slice(0, 4).forEach(function (warning) { return noteLines.push("- ".concat(warning)); });
|
|
3730
|
+
if (!content) {
|
|
3731
|
+
return noteLines.join('\n');
|
|
3732
|
+
}
|
|
3733
|
+
return "".concat(content, "\n\n").concat(noteLines.join('\n')).trim();
|
|
3734
|
+
}
|
|
3190
3735
|
function buildAssistantDebugPayload(params) {
|
|
3191
3736
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
|
|
3192
3737
|
var notes = [];
|
|
@@ -3363,7 +3908,7 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
3363
3908
|
? "Open ".concat(routeHint, " in the app to view this data or request access.")
|
|
3364
3909
|
: 'Open the related screen in the app to view this data or request access.';
|
|
3365
3910
|
if (!routeHint && collection && requiresInvoicePermission(collection)) {
|
|
3366
|
-
routeLine = 'Open /invoice/list or /report/
|
|
3911
|
+
routeLine = 'Open /invoice/list or /report-builder/list to view this data or request access.';
|
|
3367
3912
|
}
|
|
3368
3913
|
if (normalized.includes('permission scope required')) {
|
|
3369
3914
|
return "I need a permission scope to access that data. ".concat(routeLine);
|
|
@@ -3377,6 +3922,9 @@ function buildAssistantToolErrorMessage(error, directive, request) {
|
|
|
3377
3922
|
if (normalized.includes('database access denied')) {
|
|
3378
3923
|
return "Database access is restricted for that request. ".concat(routeLine);
|
|
3379
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
|
+
}
|
|
3380
3928
|
if (normalized.includes('report builder bridge') && normalized.includes('not configured')) {
|
|
3381
3929
|
return "That dataset is not configured for report builder access yet. ".concat(routeLine);
|
|
3382
3930
|
}
|
|
@@ -4876,6 +5424,7 @@ function getAssistantCurrencyFormatter() {
|
|
|
4876
5424
|
assistantCurrencyFormatter = new Intl.NumberFormat(AI_ASSISTANT_LOCALE, {
|
|
4877
5425
|
style: 'currency',
|
|
4878
5426
|
currency: AI_ASSISTANT_CURRENCY_CODE,
|
|
5427
|
+
currencyDisplay: 'narrowSymbol',
|
|
4879
5428
|
minimumFractionDigits: 2,
|
|
4880
5429
|
maximumFractionDigits: 2
|
|
4881
5430
|
});
|
|
@@ -4963,6 +5512,12 @@ function formatAssistantDisplayCell(value, column) {
|
|
|
4963
5512
|
if (Array.isArray(value)) {
|
|
4964
5513
|
return value.map(function (item) { return formatAssistantDisplayCell(item, column); }).filter(Boolean).join(', ');
|
|
4965
5514
|
}
|
|
5515
|
+
if (typeof value === 'string') {
|
|
5516
|
+
var normalizedCurrency = normalizeAssistantCurrencyText(value);
|
|
5517
|
+
if (normalizedCurrency !== value) {
|
|
5518
|
+
return normalizedCurrency;
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
4966
5521
|
var columnKey = String(column || '').toLowerCase();
|
|
4967
5522
|
if (isAssistantDateColumn(columnKey) && isAssistantLikelyDateValue(value)) {
|
|
4968
5523
|
return formatAssistantDateValue(value);
|
|
@@ -4998,6 +5553,13 @@ function formatAssistantDisplayCell(value, column) {
|
|
|
4998
5553
|
}
|
|
4999
5554
|
return String(value);
|
|
5000
5555
|
}
|
|
5556
|
+
function normalizeAssistantCurrencyText(value) {
|
|
5557
|
+
var raw = String(value || '');
|
|
5558
|
+
if (!raw) {
|
|
5559
|
+
return '';
|
|
5560
|
+
}
|
|
5561
|
+
return raw.replace(AI_ASSISTANT_USD_CURRENCY_TEXT_PATTERN, function (_match, amount) { return "$".concat(amount); });
|
|
5562
|
+
}
|
|
5001
5563
|
function formatDisplayTableMarkdown(display) {
|
|
5002
5564
|
if (!display || !Array.isArray(display.columns) || !display.columns.length) {
|
|
5003
5565
|
return '';
|
|
@@ -5019,7 +5581,7 @@ function stripAssistantMarkdownTables(value) {
|
|
|
5019
5581
|
if (!raw) {
|
|
5020
5582
|
return '';
|
|
5021
5583
|
}
|
|
5022
|
-
var tablePattern = /(^|\n)
|
|
5584
|
+
var tablePattern = /(^|\n)\s*\|[^\n]*\|\s*\n\s*\|[ \t:-|]+\|\s*\n(?:\s*\|[^\n]*\|\s*\n?)*/g;
|
|
5023
5585
|
var cleaned = raw.replace(tablePattern, '\n').trim();
|
|
5024
5586
|
return cleaned;
|
|
5025
5587
|
}
|
|
@@ -5067,7 +5629,7 @@ function isDisplayObjectLike(value) {
|
|
|
5067
5629
|
}
|
|
5068
5630
|
function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
5069
5631
|
return __awaiter(this, void 0, void 0, function () {
|
|
5070
|
-
var idUser, user, isSuperAdmin, normalizedPermission,
|
|
5632
|
+
var idUser, user, isSuperAdmin, normalizedCollection, normalizedPermission, requiresInvoiceAccess, hasInvoiceAccess, hasViewAccess;
|
|
5071
5633
|
var _a;
|
|
5072
5634
|
return __generator(this, function (_b) {
|
|
5073
5635
|
switch (_b.label) {
|
|
@@ -5083,20 +5645,21 @@ function ensureAssistantReadAccess(context, permissionView, collection) {
|
|
|
5083
5645
|
throw new Error('AI assistant report builder bridge: Unauthorized.');
|
|
5084
5646
|
}
|
|
5085
5647
|
isSuperAdmin = !!((_a = user === null || user === void 0 ? void 0 : user.roles) === null || _a === void 0 ? void 0 : _a.super_admin);
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5648
|
+
if (isSuperAdmin) {
|
|
5649
|
+
return [2 /*return*/, { user: user, isSuperAdmin: isSuperAdmin }];
|
|
5650
|
+
}
|
|
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.');
|
|
5098
5661
|
}
|
|
5099
|
-
|
|
5662
|
+
if (requiresInvoiceAccess && !hasInvoiceAccess) {
|
|
5100
5663
|
throw new Error('AI assistant report builder bridge: Access denied.');
|
|
5101
5664
|
}
|
|
5102
5665
|
return [2 /*return*/, { user: user, isSuperAdmin: isSuperAdmin }];
|
|
@@ -5172,6 +5735,90 @@ function sanitizeAssistantProjection(projection) {
|
|
|
5172
5735
|
return projection;
|
|
5173
5736
|
}
|
|
5174
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
|
+
}
|
|
5175
5822
|
function isMatchExpressionOperand(value) {
|
|
5176
5823
|
if (typeof value === 'string') {
|
|
5177
5824
|
return value.startsWith('$$');
|
|
@@ -5229,7 +5876,7 @@ function rewriteMatchExpressionsToExpr(match) {
|
|
|
5229
5876
|
}
|
|
5230
5877
|
var operand = nextEntry_1[op];
|
|
5231
5878
|
if (isMatchExpressionOperand(operand)) {
|
|
5232
|
-
exprClauses.push((_a = {}, _a[op] = ["$".concat(key), operand], _a));
|
|
5879
|
+
exprClauses.push((_a = {}, _a[op] = ["$".concat(key), normalizeAssistantNowExprOperand(operand)], _a));
|
|
5233
5880
|
delete nextEntry_1[op];
|
|
5234
5881
|
moved_1 = true;
|
|
5235
5882
|
}
|
|
@@ -5243,7 +5890,7 @@ function rewriteMatchExpressionsToExpr(match) {
|
|
|
5243
5890
|
return;
|
|
5244
5891
|
}
|
|
5245
5892
|
if (typeof entry === 'string' && entry.startsWith('$$')) {
|
|
5246
|
-
exprClauses.push({ $eq: ["$".concat(key), entry] });
|
|
5893
|
+
exprClauses.push({ $eq: ["$".concat(key), normalizeAssistantNowExprOperand(entry)] });
|
|
5247
5894
|
return;
|
|
5248
5895
|
}
|
|
5249
5896
|
result[key] = entry;
|
|
@@ -5320,7 +5967,7 @@ function normalizeAssistantAggregatePipeline(pipeline, collection) {
|
|
|
5320
5967
|
var statusNormalized = isInvoiceCollection ? normalizeInvoiceStatusMatch(exprRewritten) : exprRewritten;
|
|
5321
5968
|
next.$geoNear = __assign(__assign({}, next.$geoNear), { query: applyAssistantNameRegexToQuery(statusNormalized) });
|
|
5322
5969
|
}
|
|
5323
|
-
return next;
|
|
5970
|
+
return normalizeAssistantNowExprPlaceholdersDeep(next);
|
|
5324
5971
|
});
|
|
5325
5972
|
}
|
|
5326
5973
|
function buildAssistantAggregatePipeline(query, pipeline) {
|
|
@@ -6967,7 +7614,9 @@ function normalizeMongoQuery(query) {
|
|
|
6967
7614
|
throw new Error('AI assistant report builder bridge: Query contains restricted operators.');
|
|
6968
7615
|
}
|
|
6969
7616
|
var rewritten = rewriteEmbeddedMatchObjects(normalized);
|
|
6970
|
-
|
|
7617
|
+
var exprRewritten = rewriteMatchExpressionsToExpr(rewritten);
|
|
7618
|
+
var nowNormalized = normalizeAssistantNowExprPlaceholdersDeep(exprRewritten);
|
|
7619
|
+
return applyAssistantNameRegexToQuery(nowNormalized);
|
|
6971
7620
|
}
|
|
6972
7621
|
function shouldApplyAssistantNameRegex(field) {
|
|
6973
7622
|
var normalized = String(field || '').toLowerCase().trim();
|
|
@@ -7491,7 +8140,7 @@ function shouldAllowVersionCollections(message) {
|
|
|
7491
8140
|
}
|
|
7492
8141
|
function resolveReportCollectionName(permissionView, collectionNames, currentCollection) {
|
|
7493
8142
|
var normalizedView = normalizeOptionalString(permissionView).toLowerCase();
|
|
7494
|
-
if (!normalizedView.startsWith('/report
|
|
8143
|
+
if (!normalizedView.startsWith('/report-builder')) {
|
|
7495
8144
|
return null;
|
|
7496
8145
|
}
|
|
7497
8146
|
var current = stripVersionSuffix(normalizeOptionalString(currentCollection));
|
|
@@ -7499,11 +8148,6 @@ function resolveReportCollectionName(permissionView, collectionNames, currentCol
|
|
|
7499
8148
|
if (collectionNames.includes(reportCollection)) {
|
|
7500
8149
|
return reportCollection;
|
|
7501
8150
|
}
|
|
7502
|
-
var routeTail = normalizedView.replace('/report/', '').replace(/\//g, '-');
|
|
7503
|
-
var routeCandidate = routeTail ? "report-".concat(routeTail) : '';
|
|
7504
|
-
if (routeCandidate && collectionNames.includes(routeCandidate)) {
|
|
7505
|
-
return routeCandidate;
|
|
7506
|
-
}
|
|
7507
8151
|
return null;
|
|
7508
8152
|
}
|
|
7509
8153
|
function resolveBaseCollectionFromReport(db, dbName, collection) {
|
|
@@ -7541,7 +8185,7 @@ function resolveCollectionOverrideWithContext(params) {
|
|
|
7541
8185
|
to: reportPreferred,
|
|
7542
8186
|
fromScore: 0,
|
|
7543
8187
|
toScore: 0,
|
|
7544
|
-
reason: 'report route preference'
|
|
8188
|
+
reason: 'report builder route preference'
|
|
7545
8189
|
};
|
|
7546
8190
|
}
|
|
7547
8191
|
}
|
|
@@ -8149,14 +8793,43 @@ function userHasViewPermission(user, view) {
|
|
|
8149
8793
|
}
|
|
8150
8794
|
return false;
|
|
8151
8795
|
}
|
|
8152
|
-
function
|
|
8153
|
-
|
|
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) {
|
|
8154
8823
|
return false;
|
|
8155
8824
|
}
|
|
8156
|
-
|
|
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); });
|
|
8157
8830
|
}
|
|
8158
8831
|
function userHasInvoiceAccess(user) {
|
|
8159
|
-
return
|
|
8832
|
+
return userHasViewTokenPermission(user, /invoice/i);
|
|
8160
8833
|
}
|
|
8161
8834
|
function requiresInvoicePermission(collection) {
|
|
8162
8835
|
var normalized = normalizeOptionalString(collection).toLowerCase();
|
|
@@ -8208,16 +8881,59 @@ function resolveCodexWorkerThreadEnabled() {
|
|
|
8208
8881
|
}
|
|
8209
8882
|
return process.env.IS_WORKER_INSTANCE !== 'true';
|
|
8210
8883
|
}
|
|
8211
|
-
function
|
|
8212
|
-
|
|
8213
|
-
|
|
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']
|
|
8214
8904
|
|| process.env.AI_ASSISTANT_CODEX_MODEL
|
|
8215
|
-
||
|
|
8905
|
+
|| serverConfig['AI_TERMINAL_CODEX_MODEL']
|
|
8216
8906
|
|| process.env.AI_TERMINAL_CODEX_MODEL
|
|
8217
|
-
||
|
|
8907
|
+
|| serverConfig['AI_DASHBOARD_CODEX_MODEL']
|
|
8218
8908
|
|| process.env.AI_DASHBOARD_CODEX_MODEL);
|
|
8219
8909
|
return raw || DEFAULT_CODEX_MODEL;
|
|
8220
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
|
+
}
|
|
8221
8937
|
function resolveCodexThoughtLevel() {
|
|
8222
8938
|
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8223
8939
|
var raw = normalizeOptionalString(config['AI_ASSISTANT_CODEX_THOUGHT_LEVEL']
|
|
@@ -8232,25 +8948,38 @@ function resolveCodexThoughtLevel() {
|
|
|
8232
8948
|
}
|
|
8233
8949
|
return 'low';
|
|
8234
8950
|
}
|
|
8235
|
-
function resolveCodexSettings() {
|
|
8951
|
+
function resolveCodexSettings(options) {
|
|
8236
8952
|
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
8237
8953
|
var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
|
|
8238
8954
|
if (!apiKey) {
|
|
8239
8955
|
throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
|
|
8240
8956
|
}
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
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
|
+
});
|
|
8248
8972
|
}
|
|
8249
|
-
function getAssistantCodexClient() {
|
|
8250
|
-
|
|
8251
|
-
|
|
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;
|
|
8252
8979
|
}
|
|
8253
|
-
|
|
8980
|
+
var client = new codex_client_1.CodexClient(resolved);
|
|
8981
|
+
assistantCodexClientByConfig.set(key, client);
|
|
8982
|
+
return client;
|
|
8254
8983
|
}
|
|
8255
8984
|
var CodexWorkerBootstrapError = /** @class */ (function (_super) {
|
|
8256
8985
|
__extends(CodexWorkerBootstrapError, _super);
|
|
@@ -8345,14 +9074,14 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
|
|
|
8345
9074
|
case 0:
|
|
8346
9075
|
streamedOptions = applyCodexStreamStatusHandler(runOptions, streamStatusHandler);
|
|
8347
9076
|
if (!!resolveCodexWorkerThreadEnabled()) return [3 /*break*/, 2];
|
|
8348
|
-
codexClient = getAssistantCodexClient();
|
|
9077
|
+
codexClient = getAssistantCodexClient(config);
|
|
8349
9078
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8350
9079
|
case 1: return [2 /*return*/, _a.sent()];
|
|
8351
9080
|
case 2: return [4 /*yield*/, resolveCodexWorkerPath()];
|
|
8352
9081
|
case 3:
|
|
8353
9082
|
workerPath = _a.sent();
|
|
8354
9083
|
if (!!workerPath) return [3 /*break*/, 5];
|
|
8355
|
-
codexClient = getAssistantCodexClient();
|
|
9084
|
+
codexClient = getAssistantCodexClient(config);
|
|
8356
9085
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8357
9086
|
case 4: return [2 /*return*/, _a.sent()];
|
|
8358
9087
|
case 5:
|
|
@@ -8365,7 +9094,7 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
|
|
|
8365
9094
|
throw error_4;
|
|
8366
9095
|
}
|
|
8367
9096
|
console.error('Codex worker bootstrap failed, falling back to in-process run.', error_4);
|
|
8368
|
-
codexClient = getAssistantCodexClient();
|
|
9097
|
+
codexClient = getAssistantCodexClient(config);
|
|
8369
9098
|
return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
|
|
8370
9099
|
case 8: return [2 /*return*/, _a.sent()];
|
|
8371
9100
|
case 9: return [2 /*return*/];
|
|
@@ -8527,7 +9256,8 @@ function sanitizeCodexRunOptions(options) {
|
|
|
8527
9256
|
timeoutMs: options.timeoutMs,
|
|
8528
9257
|
threadOptions: options.threadOptions,
|
|
8529
9258
|
threadKey: options.threadKey,
|
|
8530
|
-
reuseThread: options.reuseThread
|
|
9259
|
+
reuseThread: options.reuseThread,
|
|
9260
|
+
fallbackModels: options.fallbackModels
|
|
8531
9261
|
};
|
|
8532
9262
|
}
|
|
8533
9263
|
function resolveCodexWorkerPath() {
|
|
@@ -8910,6 +9640,10 @@ function buildAssistantContext(input, userContext) {
|
|
|
8910
9640
|
lines.push(hint);
|
|
8911
9641
|
});
|
|
8912
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
|
+
}
|
|
8913
9647
|
var mongoDb = normalizeOptionalString((_c = input === null || input === void 0 ? void 0 : input.mongo) === null || _c === void 0 ? void 0 : _c.database);
|
|
8914
9648
|
var mongoDbs = Array.isArray((_d = input === null || input === void 0 ? void 0 : input.mongo) === null || _d === void 0 ? void 0 : _d.databases)
|
|
8915
9649
|
? input.mongo.databases.map(function (value) { return normalizeOptionalString(value); }).filter(Boolean)
|
|
@@ -9006,6 +9740,34 @@ function buildAssistantFieldHints(message, collectionNames, options) {
|
|
|
9006
9740
|
});
|
|
9007
9741
|
return hints;
|
|
9008
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
|
+
}
|
|
9009
9771
|
var cachedClientRouteIndex = null;
|
|
9010
9772
|
function normalizeRouteKey(value) {
|
|
9011
9773
|
var trimmed = normalizeOptionalString(value);
|
|
@@ -9180,13 +9942,7 @@ function sanitizeAssistantResponse(value) {
|
|
|
9180
9942
|
if (!cleaned) {
|
|
9181
9943
|
return 'I can’t share code, but I can point you to files or explain behavior at a high level.';
|
|
9182
9944
|
}
|
|
9183
|
-
var normalizedCurrency = cleaned
|
|
9184
|
-
.replace(/\bUSD(?:\s| | |[\u00A0\u202F\u2007])*\$?\s*([-+]?[0-9][0-9,]*(?:\.[0-9]+)?)/g, function (_match, amount) {
|
|
9185
|
-
return "$".concat(amount);
|
|
9186
|
-
})
|
|
9187
|
-
.replace(/\bUS\$\s*([-+]?[0-9][0-9,]*(?:\.[0-9]+)?)/g, function (_match, amount) {
|
|
9188
|
-
return "$".concat(amount);
|
|
9189
|
-
});
|
|
9945
|
+
var normalizedCurrency = normalizeAssistantCurrencyText(cleaned);
|
|
9190
9946
|
return normalizeAssistantRoutes(normalizedCurrency);
|
|
9191
9947
|
}
|
|
9192
9948
|
function evaluateAssistantGuardrails(message) {
|