@resolveio/server-lib 22.0.16 → 22.0.17

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.
@@ -544,7 +544,8 @@ var AI_ASSISTANT_PLANNER_SYSTEM_PROMPT = [
544
544
  '5) CLASSIFY THE REQUEST:',
545
545
  ' - type = "navigation" if user asks how/where to do something in the app.',
546
546
  ' - type = "data" if user asks for totals, lists, breakdowns, counts, reports, "last N", "by month", etc.',
547
- ' - type = "program_explain" if user asks how the system works (features/process).',
547
+ ' - type = "feature_info" if user asks how the system works (features/process) without requesting data.',
548
+ ' - type = "bug_issue" if user reports wrong behavior/errors or asks for root-cause/debugging.',
548
549
  ' - type = "mixed" if both navigation + data are clearly requested.',
549
550
  '',
550
551
  '6) OUTPUT FORMAT:',
@@ -579,7 +580,7 @@ var AI_ASSISTANT_PLANNER_USER_PROMPT_TEMPLATE = [
579
580
  ' }',
580
581
  ' },',
581
582
  ' "intent": {',
582
- ' "type": "navigation" | "data" | "program_explain" | "mixed",',
583
+ ' "type": "navigation" | "data" | "feature_info" | "bug_issue" | "mixed",',
583
584
  ' "summary": string,',
584
585
  ' "confidence": number',
585
586
  ' },',
@@ -779,28 +780,31 @@ function loadAiTerminalMethods(methodManager) {
779
780
  function: function (payload) {
780
781
  return __awaiter(this, void 0, void 0, function () {
781
782
  var now, doc, result;
782
- return __generator(this, function (_a) {
783
- switch (_a.label) {
783
+ var _a;
784
+ return __generator(this, function (_b) {
785
+ switch (_b.label) {
784
786
  case 0:
785
787
  now = new Date();
786
- doc = {
787
- id_client: resolveClientIdFromConfig(payload.id_client),
788
- id_app: normalizeOptionalString(payload.id_app),
789
- title: normalizeOptionalString(payload.title) || 'New Conversation',
790
- mode: normalizeConversationMode(payload.mode),
791
- branch_enabled: payload.branch_enabled === true,
792
- branch_name: normalizeOptionalString(payload.branch_name),
793
- status: normalizeConversationStatus(payload.status),
794
- profile_id: normalizeOptionalString(payload.profile_id),
795
- metadata: payload.metadata || {},
796
- last_message_at: undefined,
797
- last_message_id: undefined,
798
- createdAt: now,
799
- updatedAt: now
800
- };
801
- return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.insertOne(doc)];
788
+ _a = {};
789
+ return [4 /*yield*/, resolveClientIdFromConfig(payload.id_client, this === null || this === void 0 ? void 0 : this.id_user)];
802
790
  case 1:
803
- result = _a.sent();
791
+ doc = (_a.id_client = _b.sent(),
792
+ _a.id_app = normalizeOptionalString(payload.id_app),
793
+ _a.title = normalizeOptionalString(payload.title) || 'New Conversation',
794
+ _a.mode = normalizeConversationMode(payload.mode),
795
+ _a.branch_enabled = payload.branch_enabled === true,
796
+ _a.branch_name = normalizeOptionalString(payload.branch_name),
797
+ _a.status = normalizeConversationStatus(payload.status),
798
+ _a.profile_id = normalizeOptionalString(payload.profile_id),
799
+ _a.metadata = payload.metadata || {},
800
+ _a.last_message_at = undefined,
801
+ _a.last_message_id = undefined,
802
+ _a.createdAt = now,
803
+ _a.updatedAt = now,
804
+ _a);
805
+ return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.insertOne(doc)];
806
+ case 2:
807
+ result = _b.sent();
804
808
  return [2 /*return*/, { id_conversation: result._id }];
805
809
  }
806
810
  });
@@ -1117,7 +1121,7 @@ function executeAiTerminalRun(payload, context) {
1117
1121
  if (!guardrailsEnabled) return [3 /*break*/, 6];
1118
1122
  guardrail = evaluateGuardrails(message);
1119
1123
  if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 6];
1120
- return [4 /*yield*/, ensureConversation(input, 'openai')];
1124
+ return [4 /*yield*/, ensureConversation(input, 'openai', context === null || context === void 0 ? void 0 : context.id_user)];
1121
1125
  case 2:
1122
1126
  conversation_1 = _b.sent();
1123
1127
  now_1 = new Date();
@@ -1151,7 +1155,7 @@ function executeAiTerminalRun(payload, context) {
1151
1155
  message: assistantMsg,
1152
1156
  guardrails: { blocked: true, reason: guardrail.reason }
1153
1157
  }];
1154
- case 6: return [4 /*yield*/, ensureConversation(input, 'openai')];
1158
+ case 6: return [4 /*yield*/, ensureConversation(input, 'openai', context === null || context === void 0 ? void 0 : context.id_user)];
1155
1159
  case 7:
1156
1160
  conversation = _b.sent();
1157
1161
  now = new Date();
@@ -1194,8 +1198,10 @@ function executeAiTerminalRun(payload, context) {
1194
1198
  case 12:
1195
1199
  response = _b.sent();
1196
1200
  usage = response.usage || estimateUsage(messages, response.content, openaiSettings.model);
1197
- idClient = resolveClientId(conversation, input.id_client);
1198
- if (!idClient) return [3 /*break*/, 14];
1201
+ return [4 /*yield*/, resolveClientId(conversation, input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1202
+ case 13:
1203
+ idClient = _b.sent();
1204
+ if (!idClient) return [3 /*break*/, 15];
1199
1205
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1200
1206
  id_client: idClient,
1201
1207
  model: response.model || openaiSettings.model || 'unknown',
@@ -1205,10 +1211,10 @@ function executeAiTerminalRun(payload, context) {
1205
1211
  category: 'ai-terminal',
1206
1212
  id_conversation: conversation._id
1207
1213
  })];
1208
- case 13:
1209
- _b.sent();
1210
- _b.label = 14;
1211
1214
  case 14:
1215
+ _b.sent();
1216
+ _b.label = 15;
1217
+ case 15:
1212
1218
  userDoc = {
1213
1219
  id_conversation: conversation._id,
1214
1220
  role: 'user',
@@ -1233,20 +1239,20 @@ function executeAiTerminalRun(payload, context) {
1233
1239
  updatedAt: now
1234
1240
  };
1235
1241
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
1236
- case 15:
1242
+ case 16:
1237
1243
  _b.sent();
1238
1244
  return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
1239
- case 16:
1245
+ case 17:
1240
1246
  insertResult = _b.sent();
1241
1247
  return [4 /*yield*/, touchConversation(conversation._id, now, insertResult._id)];
1242
- case 17:
1248
+ case 18:
1243
1249
  _b.sent();
1244
- if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 19];
1250
+ if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 20];
1245
1251
  return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
1246
- case 18:
1252
+ case 19:
1247
1253
  _b.sent();
1248
- _b.label = 19;
1249
- case 19: return [2 /*return*/, {
1254
+ _b.label = 20;
1255
+ case 20: return [2 /*return*/, {
1250
1256
  conversation: conversation,
1251
1257
  message: assistantDoc,
1252
1258
  usage: assistantDoc.usage
@@ -1290,8 +1296,10 @@ function executeAiFormPatch(payload, context) {
1290
1296
  case 1:
1291
1297
  response = _b.sent();
1292
1298
  usage = response.usage || estimateUsage(messages, response.content, response.model || openaiSettings.model);
1293
- idClient = resolveClientIdFromConfig(input.id_client);
1294
- if (!idClient) return [3 /*break*/, 3];
1299
+ return [4 /*yield*/, resolveClientIdFromConfig(input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1300
+ case 2:
1301
+ idClient = _b.sent();
1302
+ if (!idClient) return [3 /*break*/, 4];
1295
1303
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1296
1304
  id_client: idClient,
1297
1305
  model: response.model || openaiSettings.model || 'unknown',
@@ -1300,10 +1308,10 @@ function executeAiFormPatch(payload, context) {
1300
1308
  total_tokens: usage.totalTokens,
1301
1309
  category: 'ai-form'
1302
1310
  })];
1303
- case 2:
1304
- _b.sent();
1305
- _b.label = 3;
1306
1311
  case 3:
1312
+ _b.sent();
1313
+ _b.label = 4;
1314
+ case 4:
1307
1315
  parsed = parseJsonObject(response.content);
1308
1316
  if (!parsed || typeof parsed !== 'object') {
1309
1317
  throw new Error('AI form patch response was not valid JSON.');
@@ -1344,7 +1352,7 @@ function executeAiAssistantCodexRun(payload, context) {
1344
1352
  codexFallbackModels = resolveCodexFallbackModels(input.config, codexModel);
1345
1353
  guardrail = evaluateAssistantGuardrails(message);
1346
1354
  if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
1347
- return [4 /*yield*/, ensureConversation(input, 'codex')];
1355
+ return [4 /*yield*/, ensureConversation(input, 'codex', context === null || context === void 0 ? void 0 : context.id_user)];
1348
1356
  case 1:
1349
1357
  conversation_2 = _d.sent();
1350
1358
  now_2 = new Date();
@@ -1384,7 +1392,7 @@ function executeAiAssistantCodexRun(payload, context) {
1384
1392
  isSuperAdmin = !!((_b = user === null || user === void 0 ? void 0 : user.roles) === null || _b === void 0 ? void 0 : _b.super_admin);
1385
1393
  hasInvoiceAccess = userHasInvoiceAccess(user);
1386
1394
  customerId = normalizeOptionalString((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.id_customer);
1387
- return [4 /*yield*/, ensureConversation(input, 'codex')];
1395
+ return [4 /*yield*/, ensureConversation(input, 'codex', context === null || context === void 0 ? void 0 : context.id_user)];
1388
1396
  case 7:
1389
1397
  conversation = _d.sent();
1390
1398
  if (aiWorkerDebug) {
@@ -1450,10 +1458,10 @@ function executeAiAssistantCodexRun(payload, context) {
1450
1458
  insertResult = _d.sent();
1451
1459
  assistantMessageId = (insertResult === null || insertResult === void 0 ? void 0 : insertResult._id) || (insertResult === null || insertResult === void 0 ? void 0 : insertResult.insertedId);
1452
1460
  enqueueAssistantCodexRun(function () { return __awaiter(_this, void 0, void 0, function () {
1453
- var runStart, steps, recordStep, progressTracker, streamProgress, assistantContent, toolResult, assistantDebug, directiveSource, dataQuestion, lastDirective, toolResponseDebug, toolError, termHints, collectionHints, fieldHints, collectionTokenization, collectionRanking, collectionSelection, collectionOverride, collectionNames, plannerEnabled, plannerOutput, plannerRaw, timingBreakdown, contextRoute, contextMode, hintSeed, termExpansion, hintText, baseTokens, expandedTokens, baseWeights, expandedWeights, dbName, db, _a, routeHints, rankedCollections, hintCollections, assistantContext, prompt_1, workspaceRoot, codexConfig, runOptions, plannerPrompt, plannerStart, _b, intentType, shouldFetch, responseText, directiveText, directive, directivePrompt, directiveStart, forcedDirective, _c, initialStart, directivePrompt, forcedStart, forcedDirective, _d, requestedCollection, cleanedResponseText, effectiveDirective, toolRequest, toolStart, toolResponse, _e, toolPayload, followupPrompt, followupStart, followupText, _f, error_2, error_3, finishedAt, finalNow, finishedAt, codexMs, draftingMs, finalMetadata, finalAssistantDoc;
1454
- var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
1455
- return __generator(this, function (_x) {
1456
- switch (_x.label) {
1461
+ var runStart, steps, recordStep, progressTracker, streamProgress, assistantContent, toolResult, assistantDebug, directiveSource, requestClassification, dataQuestion, lastDirective, toolResponseDebug, toolError, termHints, collectionHints, fieldHints, collectionTokenization, collectionRanking, collectionSelection, collectionOverride, collectionNames, plannerEnabled, plannerOutput, plannerRaw, timingBreakdown, codexUsage, accumulateCodexUsage, contextRoute, contextMode, hintSeed, termExpansion, hintText, baseTokens, expandedTokens, baseWeights, expandedWeights, dbName, db, _a, routeHints, rankedCollections, hintCollections, assistantContext, prompt_1, workspaceRoot, codexConfig, runOptions, plannerPrompt, plannerStart, _b, responseText, directiveText, directive, directivePrompt, directiveStart, forcedDirective, _c, initialStart, directivePrompt, forcedStart, forcedDirective, _d, requestedCollection, cleanedResponseText, effectiveDirective, toolRequest, toolStart, toolResponse, _e, toolPayload, followupPrompt, followupStart, followupText, _f, error_2, error_3, finishedAt, finalNow, finishedAt, codexMs, draftingMs, finalMetadata, finalUsage, usageClientId, usageError_1, finalAssistantDoc, setPayload;
1462
+ var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
1463
+ return __generator(this, function (_v) {
1464
+ switch (_v.label) {
1457
1465
  case 0:
1458
1466
  runStart = Date.now();
1459
1467
  if (aiWorkerDebug) {
@@ -1482,7 +1490,8 @@ function executeAiAssistantCodexRun(payload, context) {
1482
1490
  toolResult = null;
1483
1491
  assistantDebug = null;
1484
1492
  directiveSource = 'none';
1485
- dataQuestion = isAssistantDataQuestion(message);
1493
+ requestClassification = classifyAssistantRequestType(message);
1494
+ dataQuestion = requestClassification.dataQuestion;
1486
1495
  lastDirective = null;
1487
1496
  toolResponseDebug = null;
1488
1497
  toolError = null;
@@ -1505,12 +1514,32 @@ function executeAiAssistantCodexRun(payload, context) {
1505
1514
  toolMs: 0,
1506
1515
  followupMs: 0
1507
1516
  };
1517
+ codexUsage = {
1518
+ input_tokens: 0,
1519
+ output_tokens: 0,
1520
+ total_tokens: 0
1521
+ };
1522
+ accumulateCodexUsage = function (promptText, completionText) {
1523
+ var inputTokens = (0, tokenizer_1.countTokens)(promptText || '', codexModel);
1524
+ var outputTokens = (0, tokenizer_1.countTokens)(completionText || '', codexModel);
1525
+ if (!inputTokens && !outputTokens) {
1526
+ return;
1527
+ }
1528
+ codexUsage.input_tokens += inputTokens;
1529
+ codexUsage.output_tokens += outputTokens;
1530
+ codexUsage.total_tokens += inputTokens + outputTokens;
1531
+ };
1508
1532
  contextRoute = normalizeOptionalString((_g = input === null || input === void 0 ? void 0 : input.context) === null || _g === void 0 ? void 0 : _g.route);
1509
1533
  contextMode = normalizeOptionalString((_h = input === null || input === void 0 ? void 0 : input.context) === null || _h === void 0 ? void 0 : _h.mode);
1510
1534
  recordStep('Queued', { requestId: requestId || undefined });
1511
- _x.label = 1;
1535
+ recordStep('Planning: request classification', {
1536
+ type: requestClassification.type,
1537
+ source: requestClassification.source,
1538
+ dataQuestion: dataQuestion
1539
+ });
1540
+ _v.label = 1;
1512
1541
  case 1:
1513
- _x.trys.push([1, 35, 36, 37]);
1542
+ _v.trys.push([1, 34, 35, 36]);
1514
1543
  hintSeed = [message, contextRoute].filter(Boolean).join(' ');
1515
1544
  termExpansion = expandAssistantTermSynonyms(hintSeed);
1516
1545
  hintText = termExpansion.expanded || hintSeed;
@@ -1531,19 +1560,19 @@ function executeAiAssistantCodexRun(payload, context) {
1531
1560
  recordStep('Planning: term expansion', {
1532
1561
  termMatches: termExpansion.matches.length ? termExpansion.matches : undefined
1533
1562
  });
1534
- _x.label = 2;
1563
+ _v.label = 2;
1535
1564
  case 2:
1536
- _x.trys.push([2, 4, , 5]);
1565
+ _v.trys.push([2, 4, , 5]);
1537
1566
  dbName = resolveAssistantDatabaseName(undefined, input.mongo);
1538
1567
  db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
1539
1568
  return [4 /*yield*/, listAssistantCollections(db, dbName)];
1540
1569
  case 3:
1541
- collectionNames = _x.sent();
1570
+ collectionNames = _v.sent();
1542
1571
  collectionHints = resolveCollectionHintsFromTokens(expandedTokens, collectionNames, 5);
1543
1572
  collectionRanking = buildCollectionRankingDebugFromTokens(expandedTokens, collectionNames, 8);
1544
1573
  return [3 /*break*/, 5];
1545
1574
  case 4:
1546
- _a = _x.sent();
1575
+ _a = _v.sent();
1547
1576
  collectionHints = [];
1548
1577
  collectionRanking = collectionRanking || ((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens)
1549
1578
  ? buildCollectionRankingDebugFromTokens(collectionTokenization.expandedTokens || [], [], 0)
@@ -1579,7 +1608,7 @@ function executeAiAssistantCodexRun(payload, context) {
1579
1608
  prompt_1 = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
1580
1609
  return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
1581
1610
  case 6:
1582
- workspaceRoot = _x.sent();
1611
+ workspaceRoot = _v.sent();
1583
1612
  codexConfig = resolveCodexSettings({
1584
1613
  model: codexModel,
1585
1614
  fallbackModels: codexFallbackModels
@@ -1602,7 +1631,7 @@ function executeAiAssistantCodexRun(payload, context) {
1602
1631
  approvalPolicy: 'never'
1603
1632
  }
1604
1633
  };
1605
- if (!plannerEnabled) return [3 /*break*/, 11];
1634
+ if (!plannerEnabled) return [3 /*break*/, 10];
1606
1635
  recordStep('Planning: planner prompt');
1607
1636
  plannerPrompt = buildAssistantPlannerPrompt({
1608
1637
  message: message,
@@ -1614,120 +1643,123 @@ function executeAiAssistantCodexRun(payload, context) {
1614
1643
  fieldHints: fieldHints,
1615
1644
  inputClientId: input.id_client
1616
1645
  });
1617
- _x.label = 7;
1646
+ _v.label = 7;
1618
1647
  case 7:
1619
- _x.trys.push([7, 9, , 10]);
1648
+ _v.trys.push([7, 9, , 10]);
1620
1649
  plannerStart = Date.now();
1621
1650
  return [4 /*yield*/, runCodexInWorkerThread(plannerPrompt, runOptions, codexConfig, streamProgress)];
1622
1651
  case 8:
1623
- plannerRaw = _x.sent();
1652
+ plannerRaw = _v.sent();
1653
+ accumulateCodexUsage(plannerPrompt, plannerRaw);
1624
1654
  timingBreakdown.plannerMs = Date.now() - plannerStart;
1625
1655
  plannerOutput = parseJsonObject(plannerRaw);
1626
1656
  recordStep('Planning: planner result', { parsed: !!plannerOutput });
1627
1657
  return [3 /*break*/, 10];
1628
1658
  case 9:
1629
- _b = _x.sent();
1659
+ _b = _v.sent();
1630
1660
  recordStep('Planning: planner result', { parsed: false });
1631
1661
  return [3 /*break*/, 10];
1632
1662
  case 10:
1633
- if (plannerOutput) {
1634
- intentType = normalizeOptionalString((_j = plannerOutput === null || plannerOutput === void 0 ? void 0 : plannerOutput.intent) === null || _j === void 0 ? void 0 : _j.type).toLowerCase();
1635
- shouldFetch = ((_k = plannerOutput === null || plannerOutput === void 0 ? void 0 : plannerOutput.dataPlan) === null || _k === void 0 ? void 0 : _k.shouldFetchData) === true;
1636
- if (shouldFetch || intentType === 'data' || intentType === 'mixed') {
1637
- dataQuestion = true;
1638
- }
1639
- }
1640
- _x.label = 11;
1641
- case 11:
1663
+ requestClassification = classifyAssistantRequestType(message, plannerOutput || undefined);
1664
+ dataQuestion = requestClassification.dataQuestion;
1665
+ recordStep('Planning: request classification', {
1666
+ type: requestClassification.type,
1667
+ source: requestClassification.source,
1668
+ plannerIntentType: requestClassification.plannerIntentType || undefined,
1669
+ dataQuestion: dataQuestion
1670
+ });
1642
1671
  responseText = '';
1643
1672
  directiveText = '';
1644
1673
  directive = null;
1645
- if (!dataQuestion) return [3 /*break*/, 15];
1674
+ if (!dataQuestion) return [3 /*break*/, 14];
1646
1675
  recordStep('Directive: determine tool', { type: 'data-question' });
1647
1676
  directivePrompt = buildAssistantCodexDirectivePrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
1648
- _x.label = 12;
1649
- case 12:
1650
- _x.trys.push([12, 14, , 15]);
1677
+ _v.label = 11;
1678
+ case 11:
1679
+ _v.trys.push([11, 13, , 14]);
1651
1680
  directiveStart = Date.now();
1652
1681
  return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, runOptions, codexConfig, streamProgress)];
1653
- case 13:
1654
- directiveText = _x.sent();
1682
+ case 12:
1683
+ directiveText = _v.sent();
1684
+ accumulateCodexUsage(directivePrompt, directiveText);
1655
1685
  timingBreakdown.directiveMs = Date.now() - directiveStart;
1656
1686
  forcedDirective = extractAssistantMongoDirective(directiveText);
1657
1687
  if (forcedDirective) {
1658
1688
  directive = forcedDirective;
1659
1689
  directiveSource = 'model';
1660
1690
  lastDirective = forcedDirective;
1661
- collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_l = directive.payload) === null || _l === void 0 ? void 0 : _l.collection) || '');
1691
+ collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_j = directive.payload) === null || _j === void 0 ? void 0 : _j.collection) || '');
1662
1692
  recordStep('Directive resolved', {
1663
1693
  source: directiveSource,
1664
1694
  type: directive.type,
1665
- collection: normalizeOptionalString((_m = directive.payload) === null || _m === void 0 ? void 0 : _m.collection) || undefined,
1666
- permissionView: normalizeOptionalString((_o = directive.payload) === null || _o === void 0 ? void 0 : _o.permissionView) || undefined
1695
+ collection: normalizeOptionalString((_k = directive.payload) === null || _k === void 0 ? void 0 : _k.collection) || undefined,
1696
+ permissionView: normalizeOptionalString((_l = directive.payload) === null || _l === void 0 ? void 0 : _l.permissionView) || undefined
1667
1697
  });
1668
1698
  }
1669
- return [3 /*break*/, 15];
1699
+ return [3 /*break*/, 14];
1700
+ case 13:
1701
+ _c = _v.sent();
1702
+ return [3 /*break*/, 14];
1670
1703
  case 14:
1671
- _c = _x.sent();
1672
- return [3 /*break*/, 15];
1673
- case 15:
1674
- if (!!directive) return [3 /*break*/, 17];
1704
+ if (!!directive) return [3 /*break*/, 16];
1675
1705
  recordStep('Response: draft initial answer', { mode: 'full' });
1676
1706
  initialStart = Date.now();
1677
1707
  return [4 /*yield*/, runCodexInWorkerThread(prompt_1, runOptions, codexConfig, streamProgress)];
1678
- case 16:
1679
- responseText = _x.sent();
1708
+ case 15:
1709
+ responseText = _v.sent();
1710
+ accumulateCodexUsage(prompt_1, responseText);
1680
1711
  timingBreakdown.initialResponseMs = Date.now() - initialStart;
1681
1712
  directive = extractAssistantMongoDirective(responseText);
1682
1713
  if (directive) {
1683
1714
  directiveSource = 'model';
1684
1715
  lastDirective = directive;
1685
- collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_p = directive.payload) === null || _p === void 0 ? void 0 : _p.collection) || '');
1716
+ collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_m = directive.payload) === null || _m === void 0 ? void 0 : _m.collection) || '');
1686
1717
  recordStep('Directive resolved', {
1687
1718
  source: directiveSource,
1688
1719
  type: directive.type,
1689
- collection: normalizeOptionalString((_q = directive.payload) === null || _q === void 0 ? void 0 : _q.collection) || undefined,
1690
- permissionView: normalizeOptionalString((_r = directive.payload) === null || _r === void 0 ? void 0 : _r.permissionView) || undefined
1720
+ collection: normalizeOptionalString((_o = directive.payload) === null || _o === void 0 ? void 0 : _o.collection) || undefined,
1721
+ permissionView: normalizeOptionalString((_p = directive.payload) === null || _p === void 0 ? void 0 : _p.permissionView) || undefined
1691
1722
  });
1692
1723
  }
1693
- _x.label = 17;
1694
- case 17:
1695
- if (!(!directive && dataQuestion)) return [3 /*break*/, 21];
1724
+ _v.label = 16;
1725
+ case 16:
1726
+ if (!(!directive && dataQuestion)) return [3 /*break*/, 20];
1696
1727
  recordStep('Directive: forced retry', { mode: 'directive-only' });
1697
1728
  directivePrompt = buildAssistantCodexDirectivePrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext);
1698
- _x.label = 18;
1699
- case 18:
1700
- _x.trys.push([18, 20, , 21]);
1729
+ _v.label = 17;
1730
+ case 17:
1731
+ _v.trys.push([17, 19, , 20]);
1701
1732
  forcedStart = Date.now();
1702
1733
  return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, runOptions, codexConfig, streamProgress)];
1703
- case 19:
1704
- directiveText = _x.sent();
1734
+ case 18:
1735
+ directiveText = _v.sent();
1736
+ accumulateCodexUsage(directivePrompt, directiveText);
1705
1737
  timingBreakdown.forcedDirectiveMs = Date.now() - forcedStart;
1706
1738
  forcedDirective = extractAssistantMongoDirective(directiveText);
1707
1739
  if (forcedDirective) {
1708
1740
  directive = forcedDirective;
1709
1741
  directiveSource = 'forced';
1710
1742
  lastDirective = forcedDirective;
1711
- collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_s = directive.payload) === null || _s === void 0 ? void 0 : _s.collection) || '');
1743
+ collectionSelection = buildCollectionSelectionDetail((collectionTokenization === null || collectionTokenization === void 0 ? void 0 : collectionTokenization.expandedTokens) || [], normalizeOptionalString((_q = directive.payload) === null || _q === void 0 ? void 0 : _q.collection) || '');
1712
1744
  recordStep('Directive resolved', {
1713
1745
  source: directiveSource,
1714
1746
  type: directive.type,
1715
- collection: normalizeOptionalString((_t = directive.payload) === null || _t === void 0 ? void 0 : _t.collection) || undefined,
1716
- permissionView: normalizeOptionalString((_u = directive.payload) === null || _u === void 0 ? void 0 : _u.permissionView) || undefined
1747
+ collection: normalizeOptionalString((_r = directive.payload) === null || _r === void 0 ? void 0 : _r.collection) || undefined,
1748
+ permissionView: normalizeOptionalString((_s = directive.payload) === null || _s === void 0 ? void 0 : _s.permissionView) || undefined
1717
1749
  });
1718
1750
  }
1719
- return [3 /*break*/, 21];
1751
+ return [3 /*break*/, 20];
1752
+ case 19:
1753
+ _d = _v.sent();
1754
+ return [3 /*break*/, 20];
1720
1755
  case 20:
1721
- _d = _x.sent();
1722
- return [3 /*break*/, 21];
1723
- case 21:
1724
1756
  if (directive) {
1725
- requestedCollection = normalizeOptionalString((_v = directive.payload) === null || _v === void 0 ? void 0 : _v.collection);
1757
+ requestedCollection = normalizeOptionalString((_t = directive.payload) === null || _t === void 0 ? void 0 : _t.collection);
1726
1758
  collectionOverride = resolveCollectionOverrideWithContext({
1727
1759
  message: message,
1728
1760
  collectionRanking: collectionRanking,
1729
1761
  requestedCollection: requestedCollection,
1730
- permissionView: normalizeOptionalString((_w = directive.payload) === null || _w === void 0 ? void 0 : _w.permissionView) || contextRoute,
1762
+ permissionView: normalizeOptionalString((_u = directive.payload) === null || _u === void 0 ? void 0 : _u.permissionView) || contextRoute,
1731
1763
  collectionNames: collectionNames
1732
1764
  });
1733
1765
  if (collectionOverride) {
@@ -1743,7 +1775,7 @@ function executeAiAssistantCodexRun(payload, context) {
1743
1775
  if (cleanedResponseText) {
1744
1776
  assistantContent = sanitizeAssistantResponse(cleanedResponseText);
1745
1777
  }
1746
- if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 33];
1778
+ if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 32];
1747
1779
  effectiveDirective = collectionOverride
1748
1780
  ? __assign(__assign({}, directive), { payload: __assign(__assign({}, (directive.payload || {})), { collection: collectionOverride.to }) }) : directive;
1749
1781
  toolRequest = buildAssistantToolRequest(effectiveDirective, input);
@@ -1753,20 +1785,20 @@ function executeAiAssistantCodexRun(payload, context) {
1753
1785
  collection: normalizeOptionalString(toolRequest === null || toolRequest === void 0 ? void 0 : toolRequest.collection) || undefined,
1754
1786
  permissionView: normalizeOptionalString(toolRequest === null || toolRequest === void 0 ? void 0 : toolRequest.permissionView) || undefined
1755
1787
  });
1756
- _x.label = 22;
1757
- case 22:
1758
- _x.trys.push([22, 31, , 32]);
1788
+ _v.label = 21;
1789
+ case 21:
1790
+ _v.trys.push([21, 30, , 31]);
1759
1791
  toolStart = Date.now();
1760
- if (!(effectiveDirective.type === 'aggregate')) return [3 /*break*/, 24];
1792
+ if (!(effectiveDirective.type === 'aggregate')) return [3 /*break*/, 23];
1761
1793
  return [4 /*yield*/, executeAiAssistantReportBuilderAggregate(toolRequest, context)];
1762
- case 23:
1763
- _e = _x.sent();
1764
- return [3 /*break*/, 26];
1765
- case 24: return [4 /*yield*/, executeAiAssistantReportBuilderRead(toolRequest, context)];
1794
+ case 22:
1795
+ _e = _v.sent();
1796
+ return [3 /*break*/, 25];
1797
+ case 23: return [4 /*yield*/, executeAiAssistantReportBuilderRead(toolRequest, context)];
1798
+ case 24:
1799
+ _e = _v.sent();
1800
+ _v.label = 25;
1766
1801
  case 25:
1767
- _e = _x.sent();
1768
- _x.label = 26;
1769
- case 26:
1770
1802
  toolResponse = _e;
1771
1803
  timingBreakdown.toolMs = Date.now() - toolStart;
1772
1804
  toolResponseDebug = (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) && typeof toolResponse.debug === 'object'
@@ -1782,42 +1814,43 @@ function executeAiAssistantCodexRun(payload, context) {
1782
1814
  progressTracker.push('Drafting response');
1783
1815
  recordStep('Drafting response');
1784
1816
  followupPrompt = buildAssistantCodexToolFollowupPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, toolPayload.prompt);
1785
- _x.label = 27;
1786
- case 27:
1787
- _x.trys.push([27, 29, , 30]);
1817
+ _v.label = 26;
1818
+ case 26:
1819
+ _v.trys.push([26, 28, , 29]);
1788
1820
  followupStart = Date.now();
1789
1821
  return [4 /*yield*/, runCodexInWorkerThread(followupPrompt, runOptions, codexConfig, streamProgress)];
1790
- case 28:
1791
- followupText = _x.sent();
1822
+ case 27:
1823
+ followupText = _v.sent();
1824
+ accumulateCodexUsage(followupPrompt, followupText);
1792
1825
  timingBreakdown.followupMs = Date.now() - followupStart;
1793
1826
  assistantContent = sanitizeAssistantResponse(followupText);
1794
1827
  assistantContent = applyAssistantDisplayTableToResponse(assistantContent, toolPayload.result.output.display);
1795
- return [3 /*break*/, 30];
1796
- case 29:
1797
- _f = _x.sent();
1828
+ return [3 /*break*/, 29];
1829
+ case 28:
1830
+ _f = _v.sent();
1798
1831
  assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
1799
- return [3 /*break*/, 30];
1800
- case 30: return [3 /*break*/, 32];
1801
- case 31:
1802
- error_2 = _x.sent();
1803
- assistantContent = buildAssistantToolErrorMessage(error_2, directive, toolRequest);
1832
+ return [3 /*break*/, 29];
1833
+ case 29: return [3 /*break*/, 31];
1834
+ case 30:
1835
+ error_2 = _v.sent();
1836
+ assistantContent = buildAssistantToolErrorMessage(error_2);
1804
1837
  toolError = error_2;
1805
- return [3 /*break*/, 32];
1806
- case 32: return [3 /*break*/, 34];
1807
- case 33:
1838
+ return [3 /*break*/, 31];
1839
+ case 31: return [3 /*break*/, 33];
1840
+ case 32:
1808
1841
  progressTracker.push('Drafting response');
1809
1842
  recordStep('Drafting response');
1810
- _x.label = 34;
1811
- case 34: return [3 /*break*/, 37];
1812
- case 35:
1813
- error_3 = _x.sent();
1843
+ _v.label = 33;
1844
+ case 33: return [3 /*break*/, 36];
1845
+ case 34:
1846
+ error_3 = _v.sent();
1814
1847
  assistantContent = buildAssistantCodexErrorMessage(error_3);
1815
1848
  recordStep('Error', { message: normalizeOptionalString(error_3 === null || error_3 === void 0 ? void 0 : error_3.message) || 'Unknown error' });
1816
- return [3 /*break*/, 37];
1817
- case 36:
1849
+ return [3 /*break*/, 36];
1850
+ case 35:
1818
1851
  progressTracker.stop();
1819
1852
  return [7 /*endfinally*/];
1820
- case 37:
1853
+ case 36:
1821
1854
  if (!assistantContent) {
1822
1855
  assistantContent = buildAssistantCodexErrorMessage(null);
1823
1856
  }
@@ -1849,6 +1882,9 @@ function executeAiAssistantCodexRun(payload, context) {
1849
1882
  + timingBreakdown.followupMs;
1850
1883
  draftingMs = timingBreakdown.followupMs || timingBreakdown.initialResponseMs;
1851
1884
  assistantDebug = buildAssistantDebugPayload({
1885
+ requestType: requestClassification.type,
1886
+ requestTypeSource: requestClassification.source,
1887
+ plannerIntentType: requestClassification.plannerIntentType,
1852
1888
  dataQuestion: dataQuestion,
1853
1889
  directive: lastDirective,
1854
1890
  directiveSource: directiveSource,
@@ -1894,27 +1930,63 @@ function executeAiAssistantCodexRun(payload, context) {
1894
1930
  });
1895
1931
  }
1896
1932
  finalMetadata = __assign(__assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), (toolResult ? { tool_result: toolResult } : {})), (assistantDebug ? { debug: assistantDebug } : {}));
1897
- finalAssistantDoc = __assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata, updatedAt: finalNow });
1898
- if (!assistantMessageId) return [3 /*break*/, 39];
1899
- return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: assistantMessageId }, {
1900
- $set: {
1901
- content: assistantContent,
1902
- metadata: finalMetadata,
1903
- updatedAt: finalNow
1904
- }
1905
- })];
1933
+ finalUsage = codexUsage.total_tokens > 0 ? {
1934
+ model: codexModel || 'unknown',
1935
+ input_tokens: codexUsage.input_tokens,
1936
+ output_tokens: codexUsage.output_tokens,
1937
+ total_tokens: codexUsage.total_tokens
1938
+ } : null;
1939
+ if (!finalUsage) return [3 /*break*/, 41];
1940
+ return [4 /*yield*/, resolveClientId(conversation, input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1941
+ case 37:
1942
+ usageClientId = _v.sent();
1943
+ if (!usageClientId) return [3 /*break*/, 41];
1944
+ _v.label = 38;
1906
1945
  case 38:
1907
- _x.sent();
1908
- _x.label = 39;
1909
- case 39: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
1946
+ _v.trys.push([38, 40, , 41]);
1947
+ return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1948
+ id_client: usageClientId,
1949
+ model: finalUsage.model,
1950
+ input_tokens: finalUsage.input_tokens,
1951
+ output_tokens: finalUsage.output_tokens,
1952
+ total_tokens: finalUsage.total_tokens,
1953
+ category: 'ai-terminal-codex',
1954
+ id_request: requestId || undefined,
1955
+ id_conversation: conversation._id
1956
+ })];
1957
+ case 39:
1958
+ _v.sent();
1959
+ return [3 /*break*/, 41];
1910
1960
  case 40:
1911
- _x.sent();
1912
- if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 42];
1913
- return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
1961
+ usageError_1 = _v.sent();
1962
+ console.error(new Date(), 'Failed to record codex usage', usageError_1);
1963
+ return [3 /*break*/, 41];
1914
1964
  case 41:
1915
- _x.sent();
1916
- _x.label = 42;
1917
- case 42: return [2 /*return*/, finalAssistantDoc];
1965
+ finalAssistantDoc = __assign(__assign(__assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata }), (finalUsage ? { usage: finalUsage } : {})), { updatedAt: finalNow });
1966
+ if (!assistantMessageId) return [3 /*break*/, 43];
1967
+ setPayload = {
1968
+ content: assistantContent,
1969
+ metadata: finalMetadata,
1970
+ updatedAt: finalNow
1971
+ };
1972
+ if (finalUsage) {
1973
+ setPayload.usage = finalUsage;
1974
+ }
1975
+ return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: assistantMessageId }, {
1976
+ $set: setPayload
1977
+ })];
1978
+ case 42:
1979
+ _v.sent();
1980
+ _v.label = 43;
1981
+ case 43: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
1982
+ case 44:
1983
+ _v.sent();
1984
+ if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 46];
1985
+ return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
1986
+ case 45:
1987
+ _v.sent();
1988
+ _v.label = 46;
1989
+ case 46: return [2 /*return*/, finalAssistantDoc];
1918
1990
  }
1919
1991
  });
1920
1992
  }); });
@@ -2423,7 +2495,8 @@ function executeAiAssistantMongoRead(payload, context) {
2423
2495
  }
2424
2496
  function executeAiAssistantMongoAggregate(payload, context) {
2425
2497
  return __awaiter(this, void 0, void 0, function () {
2426
- 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;
2498
+ 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, executedPipeline, dateField, aggregateOptions, runAggregateWithRepair, initialAggregate, documents, probeDocs, fallback, fallbackPipeline, fallbackAggregate, fallbackDocs, createdFallback, createdPipeline, createdAggregate, createdDocs, expanded, expandedAggregate, expandedDocs, completionFallback, fallbackPipeline, fallbackAggregate, fallbackDocs, completionExprFallback, fallbackPipeline, fallbackAggregate, fallbackDocs, unwindFallback, shouldUnwind, _c, _d, fallbackPipeline, fallbackAggregate, fallbackDocs, nameFallback, fallbackPipeline, fallbackAggregate, fallbackDocs, _e, _loop_1, i, state_1, matchFields_1, _f, aliases, rewrittenPipeline, fallbackAggregate, 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;
2499
+ var _this = this;
2427
2500
  var _o, _p;
2428
2501
  return __generator(this, function (_q) {
2429
2502
  switch (_q.label) {
@@ -2507,49 +2580,85 @@ function executeAiAssistantMongoAggregate(payload, context) {
2507
2580
  pipelineWithScope = buildAssistantAggregatePipeline(scopedQuery, sanitizedPipeline);
2508
2581
  normalizedOptions = normalizeAssistantAggregateOptions(input.options);
2509
2582
  limitedPipeline = applyAssistantAggregateLimit(pipelineWithScope, normalizedOptions.limit, normalizedOptions.maxLimit, normalizedOptions.defaultLimit);
2510
- dateField = findAggregateDateField(limitedPipeline);
2511
- if (containsForbiddenMongoOperators(limitedPipeline)) {
2583
+ executedPipeline = limitedPipeline;
2584
+ dateField = findAggregateDateField(executedPipeline);
2585
+ if (containsForbiddenMongoOperators(executedPipeline)) {
2512
2586
  throw new Error('AI assistant report builder bridge: Pipeline contains restricted operators.');
2513
2587
  }
2514
2588
  aggregateOptions = __assign(__assign({}, normalizedOptions.aggregateOptions), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
2515
- return [4 /*yield*/, db.collection(collection)
2516
- .aggregate(limitedPipeline, aggregateOptions)
2517
- .toArray()];
2589
+ runAggregateWithRepair = function (pipeline, stage) { return __awaiter(_this, void 0, void 0, function () {
2590
+ var docs, error_4, repaired, docs;
2591
+ return __generator(this, function (_a) {
2592
+ switch (_a.label) {
2593
+ case 0:
2594
+ _a.trys.push([0, 2, , 4]);
2595
+ return [4 /*yield*/, db.collection(collection)
2596
+ .aggregate(pipeline, aggregateOptions)
2597
+ .toArray()];
2598
+ case 1:
2599
+ docs = _a.sent();
2600
+ return [2 /*return*/, { documents: docs, pipeline: pipeline }];
2601
+ case 2:
2602
+ error_4 = _a.sent();
2603
+ if (!isAssistantDateArithmeticArgumentError(error_4)) {
2604
+ throw error_4;
2605
+ }
2606
+ repaired = repairAssistantDateArithmeticInPipeline(pipeline);
2607
+ if (!repaired.changed || containsForbiddenMongoOperators(repaired.pipeline)) {
2608
+ throw error_4;
2609
+ }
2610
+ return [4 /*yield*/, db.collection(collection)
2611
+ .aggregate(repaired.pipeline, aggregateOptions)
2612
+ .toArray()];
2613
+ case 3:
2614
+ docs = _a.sent();
2615
+ fallbackMeta.dateArithmetic = {
2616
+ attempted: true,
2617
+ used: true,
2618
+ stage: stage,
2619
+ reason: 'normalized_date_operator_args'
2620
+ };
2621
+ return [2 /*return*/, { documents: docs, pipeline: repaired.pipeline }];
2622
+ case 4: return [2 /*return*/];
2623
+ }
2624
+ });
2625
+ }); };
2626
+ return [4 /*yield*/, runAggregateWithRepair(executedPipeline, 'initial')];
2518
2627
  case 6:
2519
- documents = _q.sent();
2520
- executedPipeline = limitedPipeline;
2628
+ initialAggregate = _q.sent();
2629
+ documents = initialAggregate.documents;
2630
+ executedPipeline = initialAggregate.pipeline;
2631
+ dateField = findAggregateDateField(executedPipeline);
2521
2632
  probeDocs = null;
2522
2633
  if (!(!documents.length && dateField)) return [3 /*break*/, 10];
2523
- fallback = resolveAggregateDateFieldFallback(limitedPipeline);
2634
+ fallback = resolveAggregateDateFieldFallback(executedPipeline);
2524
2635
  if (!fallback) return [3 /*break*/, 8];
2525
2636
  fallbackMeta.dateField = __assign(__assign({}, fallback), { attempted: true, used: false });
2526
- fallbackPipeline = replaceAggregateDateField(limitedPipeline, fallback.from, fallback.to);
2637
+ fallbackPipeline = replaceAggregateDateField(executedPipeline, fallback.from, fallback.to);
2527
2638
  if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 8];
2528
- return [4 /*yield*/, db.collection(collection)
2529
- .aggregate(fallbackPipeline, aggregateOptions)
2530
- .toArray()];
2639
+ return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'date_field_fallback')];
2531
2640
  case 7:
2532
- fallbackDocs = _q.sent();
2641
+ fallbackAggregate = _q.sent();
2642
+ fallbackDocs = fallbackAggregate.documents;
2533
2643
  if (fallbackDocs.length) {
2534
2644
  documents = fallbackDocs;
2535
- executedPipeline = fallbackPipeline;
2645
+ executedPipeline = fallbackAggregate.pipeline;
2536
2646
  fallbackMeta.dateField.used = true;
2537
2647
  }
2538
2648
  _q.label = 8;
2539
2649
  case 8:
2540
2650
  if (!(!documents.length && dateField !== 'createdAt')) return [3 /*break*/, 10];
2541
2651
  createdFallback = { from: dateField, to: 'createdAt', attempted: true, used: false };
2542
- createdPipeline = replaceAggregateDateField(limitedPipeline, dateField, 'createdAt');
2652
+ createdPipeline = replaceAggregateDateField(executedPipeline, dateField, 'createdAt');
2543
2653
  fallbackMeta.dateFieldCreatedAt = createdFallback;
2544
2654
  if (!!containsForbiddenMongoOperators(createdPipeline)) return [3 /*break*/, 10];
2545
- return [4 /*yield*/, db.collection(collection)
2546
- .aggregate(createdPipeline, aggregateOptions)
2547
- .toArray()];
2655
+ return [4 /*yield*/, runAggregateWithRepair(createdPipeline, 'date_field_created_at')];
2548
2656
  case 9:
2549
- createdDocs = _q.sent();
2657
+ createdAggregate = _q.sent();
2658
+ createdDocs = createdAggregate.documents;
2550
2659
  if (createdDocs.length) {
2551
2660
  documents = createdDocs;
2552
- executedPipeline = createdPipeline;
2661
+ executedPipeline = createdAggregate.pipeline;
2553
2662
  fallbackMeta.dateFieldCreatedAt.used = true;
2554
2663
  }
2555
2664
  _q.label = 10;
@@ -2563,14 +2672,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2563
2672
  used: false
2564
2673
  };
2565
2674
  if (!!containsForbiddenMongoOperators(expanded.pipeline)) return [3 /*break*/, 12];
2566
- return [4 /*yield*/, db.collection(collection)
2567
- .aggregate(expanded.pipeline, aggregateOptions)
2568
- .toArray()];
2675
+ return [4 /*yield*/, runAggregateWithRepair(expanded.pipeline, 'date_fields_expanded')];
2569
2676
  case 11:
2570
- expandedDocs = _q.sent();
2677
+ expandedAggregate = _q.sent();
2678
+ expandedDocs = expandedAggregate.documents;
2571
2679
  if (expandedDocs.length) {
2572
2680
  documents = expandedDocs;
2573
- executedPipeline = expanded.pipeline;
2681
+ executedPipeline = expandedAggregate.pipeline;
2574
2682
  fallbackMeta.dateFieldsExpanded.used = true;
2575
2683
  }
2576
2684
  _q.label = 12;
@@ -2588,14 +2696,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2588
2696
  };
2589
2697
  fallbackPipeline = buildAggregateCompletionFallbackPipeline(executedPipeline, completionFallback);
2590
2698
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 14];
2591
- return [4 /*yield*/, db.collection(collection)
2592
- .aggregate(fallbackPipeline, aggregateOptions)
2593
- .toArray()];
2699
+ return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'completion_add_fields')];
2594
2700
  case 13:
2595
- fallbackDocs = _q.sent();
2701
+ fallbackAggregate = _q.sent();
2702
+ fallbackDocs = fallbackAggregate.documents;
2596
2703
  if (fallbackDocs.length) {
2597
2704
  documents = fallbackDocs;
2598
- executedPipeline = fallbackPipeline;
2705
+ executedPipeline = fallbackAggregate.pipeline;
2599
2706
  fallbackMeta.completion.used = true;
2600
2707
  }
2601
2708
  _q.label = 14;
@@ -2613,14 +2720,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2613
2720
  };
2614
2721
  fallbackPipeline = buildAggregateCompletionExprFallbackPipeline(executedPipeline, completionExprFallback);
2615
2722
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 16];
2616
- return [4 /*yield*/, db.collection(collection)
2617
- .aggregate(fallbackPipeline, aggregateOptions)
2618
- .toArray()];
2723
+ return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'completion_expr')];
2619
2724
  case 15:
2620
- fallbackDocs = _q.sent();
2725
+ fallbackAggregate = _q.sent();
2726
+ fallbackDocs = fallbackAggregate.documents;
2621
2727
  if (fallbackDocs.length) {
2622
2728
  documents = fallbackDocs;
2623
- executedPipeline = fallbackPipeline;
2729
+ executedPipeline = fallbackAggregate.pipeline;
2624
2730
  fallbackMeta.completion.used = true;
2625
2731
  }
2626
2732
  _q.label = 16;
@@ -2658,14 +2764,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2658
2764
  if (!shouldUnwind) return [3 /*break*/, 24];
2659
2765
  fallbackPipeline = buildAggregateUnwindFallbackPipeline(executedPipeline, unwindFallback);
2660
2766
  if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 23];
2661
- return [4 /*yield*/, db.collection(collection)
2662
- .aggregate(fallbackPipeline, aggregateOptions)
2663
- .toArray()];
2767
+ return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'unwind')];
2664
2768
  case 22:
2665
- fallbackDocs = _q.sent();
2769
+ fallbackAggregate = _q.sent();
2770
+ fallbackDocs = fallbackAggregate.documents;
2666
2771
  if (fallbackDocs.length > documents.length) {
2667
2772
  documents = fallbackDocs;
2668
- executedPipeline = fallbackPipeline;
2773
+ executedPipeline = fallbackAggregate.pipeline;
2669
2774
  fallbackMeta.unwind.used = true;
2670
2775
  }
2671
2776
  _q.label = 23;
@@ -2685,14 +2790,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2685
2790
  };
2686
2791
  fallbackPipeline = buildAggregateNameMatchFallbackPipeline(executedPipeline, nameFallback);
2687
2792
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 27];
2688
- return [4 /*yield*/, db.collection(collection)
2689
- .aggregate(fallbackPipeline, aggregateOptions)
2690
- .toArray()];
2793
+ return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'name_match')];
2691
2794
  case 26:
2692
- fallbackDocs = _q.sent();
2795
+ fallbackAggregate = _q.sent();
2796
+ fallbackDocs = fallbackAggregate.documents;
2693
2797
  if (fallbackDocs.length) {
2694
2798
  documents = fallbackDocs;
2695
- executedPipeline = fallbackPipeline;
2799
+ executedPipeline = fallbackAggregate.pipeline;
2696
2800
  fallbackMeta.nameMatch.used = true;
2697
2801
  }
2698
2802
  _q.label = 27;
@@ -2714,7 +2818,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
2714
2818
  case 29:
2715
2819
  probeDocs = _e;
2716
2820
  _loop_1 = function (i) {
2717
- var stage, chemicalLookup, rewrittenPipeline, fallbackDocs;
2821
+ var stage, chemicalLookup, rewrittenPipeline, fallbackAggregate, fallbackDocs;
2718
2822
  return __generator(this, function (_r) {
2719
2823
  switch (_r.label) {
2720
2824
  case 0:
@@ -2739,14 +2843,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2739
2843
  fallbackMeta.chemicalLookup = __assign(__assign({}, chemicalLookup.meta), { attempted: true, used: false, stage: i });
2740
2844
  rewrittenPipeline = executedPipeline.map(function (current, index) { return (index === i ? { $match: chemicalLookup.query } : current); });
2741
2845
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 3];
2742
- return [4 /*yield*/, db.collection(collection)
2743
- .aggregate(rewrittenPipeline, aggregateOptions)
2744
- .toArray()];
2846
+ return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'chemical_lookup')];
2745
2847
  case 2:
2746
- fallbackDocs = _r.sent();
2848
+ fallbackAggregate = _r.sent();
2849
+ fallbackDocs = fallbackAggregate.documents;
2747
2850
  if (fallbackDocs.length) {
2748
2851
  documents = fallbackDocs;
2749
- executedPipeline = rewrittenPipeline;
2852
+ executedPipeline = fallbackAggregate.pipeline;
2750
2853
  fallbackMeta.chemicalLookup.used = true;
2751
2854
  return [2 /*return*/, "break"];
2752
2855
  }
@@ -2808,21 +2911,20 @@ function executeAiAssistantMongoAggregate(payload, context) {
2808
2911
  return replaceFieldPathDeep(acc, from, to);
2809
2912
  }, executedPipeline);
2810
2913
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 37];
2811
- return [4 /*yield*/, db.collection(collection)
2812
- .aggregate(rewrittenPipeline, aggregateOptions)
2813
- .toArray()];
2914
+ return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'query_field_aliases')];
2814
2915
  case 36:
2815
- fallbackDocs = _q.sent();
2916
+ fallbackAggregate = _q.sent();
2917
+ fallbackDocs = fallbackAggregate.documents;
2816
2918
  if (fallbackDocs.length) {
2817
2919
  documents = fallbackDocs;
2818
- executedPipeline = rewrittenPipeline;
2920
+ executedPipeline = fallbackAggregate.pipeline;
2819
2921
  fallbackMeta.queryFieldAliases.used = true;
2820
2922
  }
2821
2923
  _q.label = 37;
2822
2924
  case 37:
2823
2925
  if (!!documents.length) return [3 /*break*/, 41];
2824
2926
  _loop_2 = function (i) {
2825
- var stage, _s, idLookup, rewrittenPipeline, fallbackDocs;
2927
+ var stage, _s, idLookup, rewrittenPipeline, fallbackAggregate, fallbackDocs;
2826
2928
  return __generator(this, function (_t) {
2827
2929
  switch (_t.label) {
2828
2930
  case 0:
@@ -2862,14 +2964,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
2862
2964
  fallbackMeta.idLookup = __assign(__assign({}, idLookup.meta), { attempted: true, used: false, stage: i });
2863
2965
  rewrittenPipeline = executedPipeline.map(function (current, index) { return (index === i ? { $match: idLookup.query } : current); });
2864
2966
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 5];
2865
- return [4 /*yield*/, db.collection(collection)
2866
- .aggregate(rewrittenPipeline, aggregateOptions)
2867
- .toArray()];
2967
+ return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'id_lookup')];
2868
2968
  case 4:
2869
- fallbackDocs = _t.sent();
2969
+ fallbackAggregate = _t.sent();
2970
+ fallbackDocs = fallbackAggregate.documents;
2870
2971
  if (fallbackDocs.length) {
2871
2972
  documents = fallbackDocs;
2872
- executedPipeline = rewrittenPipeline;
2973
+ executedPipeline = fallbackAggregate.pipeline;
2873
2974
  fallbackMeta.idLookup.used = true;
2874
2975
  return [2 /*return*/, "break"];
2875
2976
  }
@@ -3903,6 +4004,7 @@ function resolveAssistantDatedReportWindow(toolResult) {
3903
4004
  function buildAssistantDebugPayload(params) {
3904
4005
  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;
3905
4006
  var notes = [];
4007
+ notes.push("Request classification: ".concat(params.requestType, " (").concat(params.requestTypeSource, ")."));
3906
4008
  if (params.dataQuestion) {
3907
4009
  notes.push('Detected a data request; tool call required.');
3908
4010
  }
@@ -4037,6 +4139,9 @@ function buildAssistantDebugPayload(params) {
4037
4139
  }
4038
4140
  var payload = {
4039
4141
  decision: {
4142
+ requestType: params.requestType,
4143
+ requestTypeSource: params.requestTypeSource,
4144
+ plannerIntentType: params.plannerIntentType || undefined,
4040
4145
  dataQuestion: params.dataQuestion,
4041
4146
  directiveSource: params.directiveSource
4042
4147
  },
@@ -4065,56 +4170,42 @@ function buildAssistantDebugPayload(params) {
4065
4170
  }
4066
4171
  return payload;
4067
4172
  }
4068
- function buildAssistantToolErrorMessage(error, directive, request) {
4069
- var _a, _b;
4173
+ function buildAssistantToolErrorMessage(error) {
4070
4174
  var rawMessage = normalizeOptionalString(error === null || error === void 0 ? void 0 : error.message) || 'Unable to access data.';
4071
4175
  var normalized = rawMessage.toLowerCase();
4072
- var collection = normalizeOptionalString(request === null || request === void 0 ? void 0 : request.collection) || normalizeOptionalString((_a = directive.payload) === null || _a === void 0 ? void 0 : _a.collection);
4073
- 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);
4074
- var routeLine = routeHint
4075
- ? "Open ".concat(routeHint, " in the app to view this data or request access.")
4076
- : 'Request access to the related module in the app.';
4077
- if (!routeHint && collection && requiresInvoicePermission(collection)) {
4078
- routeLine = 'Open /invoice/list in the app to view this data or request access.';
4079
- }
4176
+ var cleaned = rawMessage
4177
+ .replace(/^AI assistant report builder bridge:\s*/i, '')
4178
+ .replace(/\s+/g, ' ')
4179
+ .trim()
4180
+ .replace(/\.*$/, '');
4080
4181
  if (normalized.includes('permission scope required')) {
4081
- return "I need a permission scope to access that data. ".concat(routeLine);
4182
+ return 'I couldn\'t run the data query because no permission scope was provided.';
4082
4183
  }
4083
4184
  if (normalized.includes('access denied')) {
4084
- if (collection && requiresInvoicePermission(collection)) {
4085
- return "Invoice access is required to view that data. ".concat(routeLine);
4086
- }
4087
- return "You don't have permission to view that data. ".concat(routeLine);
4185
+ return 'I couldn\'t run the data query because this account does not have permission for that dataset.';
4088
4186
  }
4089
4187
  if (normalized.includes('database access denied')) {
4090
- return "Database access is restricted for that request. ".concat(routeLine);
4188
+ return 'I couldn\'t run the data query because database access is restricted for this request.';
4091
4189
  }
4092
4190
  if (normalized.includes('undefined variable') && normalized.includes('now_minus')) {
4093
- return "The query used an unsupported relative date token. Please retry; the assistant now normalizes relative dates automatically. ".concat(routeLine);
4191
+ return 'The query used an unsupported relative date token. Please retry and I will normalize the date expression.';
4094
4192
  }
4095
4193
  if (normalized.includes('invalid character for a variable name') && (normalized.includes('now-') || normalized.includes('now+'))) {
4096
- return "The query used an unsupported relative date token. Please retry; the assistant now normalizes relative dates automatically. ".concat(routeLine);
4194
+ return 'The query used an unsupported relative date token. Please retry and I will normalize the date expression.';
4195
+ }
4196
+ if (normalized.includes('unrecognized argument to $datesubtract: date') || normalized.includes('unrecognized argument to $dateadd: date')) {
4197
+ return 'The data query failed because of an invalid date expression argument. Please retry; date arithmetic arguments are now normalized automatically.';
4097
4198
  }
4098
4199
  if (normalized.includes('report builder bridge') && normalized.includes('not configured')) {
4099
- return "That dataset is not configured for assistant data access yet. ".concat(routeLine);
4200
+ return 'That dataset is not configured for assistant data access yet.';
4100
4201
  }
4101
4202
  if (normalized.includes('collection is required')) {
4102
4203
  return 'I need a valid collection to read from. Please specify which screen or dataset you want.';
4103
4204
  }
4104
- return "I couldn't access the requested data. ".concat(routeLine);
4105
- }
4106
- function resolveAssistantErrorRouteHint(routeHint, collection) {
4107
- var normalizedHint = normalizeOptionalString(routeHint);
4108
- if (!normalizedHint) {
4109
- var fallback = resolveDefaultAssistantPermissionView(collection);
4110
- return fallback.startsWith('/report-builder') ? '' : fallback;
4111
- }
4112
- var loweredHint = normalizedHint.toLowerCase();
4113
- if (loweredHint.startsWith('/report-builder') || loweredHint === '/report' || loweredHint.startsWith('/report/')) {
4114
- var fallback = resolveDefaultAssistantPermissionView(collection);
4115
- return fallback.startsWith('/report-builder') ? '' : fallback;
4205
+ if (cleaned) {
4206
+ return "I couldn't run the data query: ".concat(cleaned, ".");
4116
4207
  }
4117
- return normalizedHint;
4208
+ return 'I couldn\'t run the requested data query.';
4118
4209
  }
4119
4210
  function deriveAssistantStreamStatus(event) {
4120
4211
  var _a;
@@ -6141,6 +6232,34 @@ function normalizeAssistantNowExprPlaceholdersDeep(value) {
6141
6232
  function normalizeAssistantNowExprPlaceholders(value) {
6142
6233
  return normalizeAssistantNowExprPlaceholdersDeep(value);
6143
6234
  }
6235
+ function isAssistantDateArithmeticArgumentError(error) {
6236
+ var message = normalizeOptionalString(error === null || error === void 0 ? void 0 : error.message).toLowerCase();
6237
+ if (!message) {
6238
+ return false;
6239
+ }
6240
+ return message.includes('unrecognized argument to $datesubtract: date')
6241
+ || message.includes('unrecognized argument to $dateadd: date')
6242
+ || message.includes('unrecognized argument to $datesubtract: start')
6243
+ || message.includes('unrecognized argument to $dateadd: start');
6244
+ }
6245
+ function didAssistantValueChange(before, after) {
6246
+ try {
6247
+ return JSON.stringify(before) !== JSON.stringify(after);
6248
+ }
6249
+ catch (_a) {
6250
+ return true;
6251
+ }
6252
+ }
6253
+ function repairAssistantDateArithmeticInPipeline(pipeline) {
6254
+ var repairedRaw = normalizeAssistantNowExprPlaceholdersDeep(pipeline);
6255
+ var repaired = Array.isArray(repairedRaw)
6256
+ ? repairedRaw
6257
+ : pipeline;
6258
+ return {
6259
+ pipeline: repaired,
6260
+ changed: didAssistantValueChange(pipeline, repaired)
6261
+ };
6262
+ }
6144
6263
  function isMatchExpressionOperand(value) {
6145
6264
  if (typeof value === 'string') {
6146
6265
  return value.startsWith('$$');
@@ -9449,7 +9568,7 @@ function waitForCodexWorkerMessage(worker, streamStatusHandler) {
9449
9568
  }
9450
9569
  function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler) {
9451
9570
  return __awaiter(this, void 0, void 0, function () {
9452
- var streamedOptions, codexClient, workerPath, codexClient, error_4, codexClient;
9571
+ var streamedOptions, codexClient, workerPath, codexClient, error_5, codexClient;
9453
9572
  return __generator(this, function (_a) {
9454
9573
  switch (_a.label) {
9455
9574
  case 0:
@@ -9470,11 +9589,11 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
9470
9589
  return [4 /*yield*/, runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config, streamStatusHandler)];
9471
9590
  case 6: return [2 /*return*/, _a.sent()];
9472
9591
  case 7:
9473
- error_4 = _a.sent();
9474
- if (!(error_4 instanceof CodexWorkerBootstrapError)) {
9475
- throw error_4;
9592
+ error_5 = _a.sent();
9593
+ if (!(error_5 instanceof CodexWorkerBootstrapError)) {
9594
+ throw error_5;
9476
9595
  }
9477
- console.error('Codex worker bootstrap failed, falling back to in-process run.', error_4);
9596
+ console.error('Codex worker bootstrap failed, falling back to in-process run.', error_5);
9478
9597
  codexClient = getAssistantCodexClient(config);
9479
9598
  return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
9480
9599
  case 8: return [2 /*return*/, _a.sent()];
@@ -9512,7 +9631,7 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config,
9512
9631
  timeoutMs = ((sanitizedOptions === null || sanitizedOptions === void 0 ? void 0 : sanitizedOptions.timeoutMs) || resolveCodexTimeoutMs()) + 15000;
9513
9632
  timeoutController = new AbortController();
9514
9633
  timeoutPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
9515
- var error_5;
9634
+ var error_6;
9516
9635
  return __generator(this, function (_a) {
9517
9636
  switch (_a.label) {
9518
9637
  case 0:
@@ -9522,11 +9641,11 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config,
9522
9641
  _a.sent();
9523
9642
  return [2 /*return*/, { type: 'timeout' }];
9524
9643
  case 2:
9525
- error_5 = _a.sent();
9526
- if ((error_5 === null || error_5 === void 0 ? void 0 : error_5.name) === 'AbortError') {
9644
+ error_6 = _a.sent();
9645
+ if ((error_6 === null || error_6 === void 0 ? void 0 : error_6.name) === 'AbortError') {
9527
9646
  return [2 /*return*/, { type: 'aborted' }];
9528
9647
  }
9529
- throw error_5;
9648
+ throw error_6;
9530
9649
  case 3: return [2 /*return*/];
9531
9650
  }
9532
9651
  });
@@ -9849,34 +9968,178 @@ function resolveAssistantWorkspaceRoot() {
9849
9968
  });
9850
9969
  });
9851
9970
  }
9971
+ var AI_ASSISTANT_DATA_REQUEST_PATTERNS = [
9972
+ /\bshow\b/,
9973
+ /\blist\b/,
9974
+ /\bhow many\b/,
9975
+ /\bcount\b/,
9976
+ /\btotal\b/,
9977
+ /\bnumber of\b/,
9978
+ /\blast\b/,
9979
+ /\brecent\b/,
9980
+ /\bthis week\b/,
9981
+ /\blast month\b/,
9982
+ /\boverdue\b/,
9983
+ /\bopen\b/,
9984
+ /\bclosed\b/,
9985
+ /\bcompleted\b/,
9986
+ /\bmissing\b/,
9987
+ /\bgroup(ed)? by\b/,
9988
+ /\bbreakdown\b/,
9989
+ /\bper day\b/,
9990
+ /\bper week\b/,
9991
+ /\bper month\b/
9992
+ ];
9993
+ var AI_ASSISTANT_NAVIGATION_REQUEST_PATTERNS = [
9994
+ /\bwhere\b/,
9995
+ /\bhow do i\b/,
9996
+ /\bhow to\b/,
9997
+ /\bnavigate\b/,
9998
+ /\bgo to\b/,
9999
+ /\bwhich screen\b/,
10000
+ /\bwhich page\b/,
10001
+ /\bwhat menu\b/,
10002
+ /\broute\b/,
10003
+ /\bpath\b/,
10004
+ /\bfind\b/
10005
+ ];
10006
+ var AI_ASSISTANT_FEATURE_INFO_PATTERNS = [
10007
+ /\bwhat is\b/,
10008
+ /\bhow does\b/,
10009
+ /\bhow .* work\b/,
10010
+ /\bfeature\b/,
10011
+ /\bworkflow\b/,
10012
+ /\bprocess\b/,
10013
+ /\bexplain\b/,
10014
+ /\bdifference between\b/
10015
+ ];
10016
+ var AI_ASSISTANT_BUG_ISSUE_PATTERNS = [
10017
+ /\bbug\b/,
10018
+ /\bissue\b/,
10019
+ /\berror\b/,
10020
+ /\bexception\b/,
10021
+ /\bfail(?:ed|ing|ure)?\b/,
10022
+ /\bbroken\b/,
10023
+ /\bnot working\b/,
10024
+ /\bdoesn['’]t work\b/,
10025
+ /\bwhy is this happening\b/,
10026
+ /\broot cause\b/,
10027
+ /\bdebug\b/,
10028
+ /\binvestigat(?:e|ion)\b/,
10029
+ /\bfix\b/,
10030
+ /\bcrash(?:ed|ing)?\b/
10031
+ ];
9852
10032
  function isAssistantDataQuestion(message) {
9853
10033
  var text = normalizeOptionalString(message).toLowerCase();
9854
10034
  if (!text) {
9855
10035
  return false;
9856
10036
  }
9857
- var patterns = [
9858
- /\bshow\b/,
9859
- /\blist\b/,
9860
- /\bhow many\b/,
9861
- /\bcount\b/,
9862
- /\btotal\b/,
9863
- /\bnumber of\b/,
9864
- /\blast\b/,
9865
- /\brecent\b/,
9866
- /\bthis week\b/,
9867
- /\blast month\b/,
9868
- /\boverdue\b/,
9869
- /\bopen\b/,
9870
- /\bclosed\b/,
9871
- /\bcompleted\b/,
9872
- /\bmissing\b/,
9873
- /\bgroup(ed)? by\b/,
9874
- /\bbreakdown\b/,
9875
- /\bper day\b/,
9876
- /\bper week\b/,
9877
- /\bper month\b/
9878
- ];
9879
- return patterns.some(function (pattern) { return pattern.test(text); });
10037
+ return AI_ASSISTANT_DATA_REQUEST_PATTERNS.some(function (pattern) { return pattern.test(text); });
10038
+ }
10039
+ function isAssistantNavigationQuestion(message) {
10040
+ var text = normalizeOptionalString(message).toLowerCase();
10041
+ if (!text) {
10042
+ return false;
10043
+ }
10044
+ return AI_ASSISTANT_NAVIGATION_REQUEST_PATTERNS.some(function (pattern) { return pattern.test(text); });
10045
+ }
10046
+ function isAssistantFeatureInfoQuestion(message) {
10047
+ var text = normalizeOptionalString(message).toLowerCase();
10048
+ if (!text) {
10049
+ return false;
10050
+ }
10051
+ return AI_ASSISTANT_FEATURE_INFO_PATTERNS.some(function (pattern) { return pattern.test(text); });
10052
+ }
10053
+ function isAssistantBugIssueQuestion(message) {
10054
+ var text = normalizeOptionalString(message).toLowerCase();
10055
+ if (!text) {
10056
+ return false;
10057
+ }
10058
+ return AI_ASSISTANT_BUG_ISSUE_PATTERNS.some(function (pattern) { return pattern.test(text); });
10059
+ }
10060
+ function normalizeAssistantPlannerIntentType(value) {
10061
+ var normalized = normalizeOptionalString(value).toLowerCase();
10062
+ if (!normalized) {
10063
+ return null;
10064
+ }
10065
+ if (normalized === 'data') {
10066
+ return 'data';
10067
+ }
10068
+ if (normalized === 'navigation') {
10069
+ return 'navigation';
10070
+ }
10071
+ if (normalized === 'mixed') {
10072
+ return 'mixed';
10073
+ }
10074
+ if (normalized === 'feature_info' || normalized === 'program_explain') {
10075
+ return 'feature_info';
10076
+ }
10077
+ if (normalized === 'bug_issue') {
10078
+ return 'bug_issue';
10079
+ }
10080
+ return null;
10081
+ }
10082
+ function classifyAssistantRequestByHeuristics(message) {
10083
+ var isData = isAssistantDataQuestion(message);
10084
+ var isNavigation = isAssistantNavigationQuestion(message);
10085
+ var isBug = isAssistantBugIssueQuestion(message);
10086
+ var isFeatureInfo = isAssistantFeatureInfoQuestion(message);
10087
+ var type = 'unknown';
10088
+ if (isData && isNavigation) {
10089
+ type = 'mixed';
10090
+ }
10091
+ else if (isData) {
10092
+ type = 'data';
10093
+ }
10094
+ else if (isNavigation) {
10095
+ type = 'navigation';
10096
+ }
10097
+ else if (isBug) {
10098
+ type = 'bug_issue';
10099
+ }
10100
+ else if (isFeatureInfo) {
10101
+ type = 'feature_info';
10102
+ }
10103
+ return {
10104
+ type: type,
10105
+ dataQuestion: type === 'data' || type === 'mixed',
10106
+ source: 'heuristic'
10107
+ };
10108
+ }
10109
+ function classifyAssistantRequestType(message, plannerOutput) {
10110
+ var _a, _b;
10111
+ var heuristic = classifyAssistantRequestByHeuristics(message);
10112
+ var plannerIntentRaw = normalizeOptionalString((_a = plannerOutput === null || plannerOutput === void 0 ? void 0 : plannerOutput.intent) === null || _a === void 0 ? void 0 : _a.type).toLowerCase();
10113
+ var plannerIntent = normalizeAssistantPlannerIntentType(plannerIntentRaw);
10114
+ var plannerShouldFetch = ((_b = plannerOutput === null || plannerOutput === void 0 ? void 0 : plannerOutput.dataPlan) === null || _b === void 0 ? void 0 : _b.shouldFetchData) === true;
10115
+ if (!plannerIntent) {
10116
+ if (plannerShouldFetch) {
10117
+ return {
10118
+ type: heuristic.type === 'navigation' ? 'mixed' : 'data',
10119
+ dataQuestion: true,
10120
+ source: heuristic.type === 'navigation' ? 'merged' : 'planner',
10121
+ plannerIntentType: plannerIntentRaw || undefined
10122
+ };
10123
+ }
10124
+ return __assign(__assign({}, heuristic), { plannerIntentType: plannerIntentRaw || undefined });
10125
+ }
10126
+ var resolvedType = plannerIntent;
10127
+ var source = 'planner';
10128
+ if (plannerShouldFetch && resolvedType !== 'data' && resolvedType !== 'mixed') {
10129
+ resolvedType = resolvedType === 'navigation' ? 'mixed' : 'data';
10130
+ source = 'merged';
10131
+ }
10132
+ if (heuristic.dataQuestion && (resolvedType === 'navigation' || resolvedType === 'feature_info' || resolvedType === 'bug_issue')) {
10133
+ resolvedType = 'mixed';
10134
+ source = 'merged';
10135
+ }
10136
+ var dataQuestion = plannerShouldFetch || resolvedType === 'data' || resolvedType === 'mixed';
10137
+ return {
10138
+ type: resolvedType,
10139
+ dataQuestion: dataQuestion,
10140
+ source: source,
10141
+ plannerIntentType: plannerIntentRaw || undefined
10142
+ };
9880
10143
  }
9881
10144
  function buildAssistantCodexDirectivePrompt(message, attachmentText, historyText, contextText) {
9882
10145
  var trimmedContext = normalizeOptionalString(contextText);
@@ -10924,15 +11187,50 @@ function sanitizeConfig(source) {
10924
11187
  max_tokens: normalizeOptionalNumber(source === null || source === void 0 ? void 0 : source.max_tokens)
10925
11188
  };
10926
11189
  }
10927
- function resolveClientIdFromConfig(explicit) {
10928
- var _a;
10929
- var config = ((_a = resolveio_server_app_1.ResolveIOServer.getServerConfig) === null || _a === void 0 ? void 0 : _a.call(resolveio_server_app_1.ResolveIOServer)) || {};
10930
- return normalizeOptionalString(explicit)
10931
- || normalizeOptionalString(config['CLIENT_ID'] || config['client_id'] || process.env.CLIENT_ID || '');
11190
+ function isLikelyObjectId(value) {
11191
+ var normalized = normalizeOptionalString(value);
11192
+ return /^[a-f0-9]{24}$/i.test(normalized);
10932
11193
  }
10933
- function ensureConversation(input, mode) {
11194
+ function resolveClientIdFromConfig(explicit, contextUserId) {
10934
11195
  return __awaiter(this, void 0, void 0, function () {
10935
- var idConversation, existing, now, doc, result;
11196
+ var explicitValue, user, userClientId, _a, config, configClientId;
11197
+ var _b, _c;
11198
+ return __generator(this, function (_d) {
11199
+ switch (_d.label) {
11200
+ case 0:
11201
+ explicitValue = normalizeOptionalString(explicit);
11202
+ if (isLikelyObjectId(explicitValue)) {
11203
+ return [2 /*return*/, explicitValue];
11204
+ }
11205
+ if (!contextUserId) return [3 /*break*/, 4];
11206
+ _d.label = 1;
11207
+ case 1:
11208
+ _d.trys.push([1, 3, , 4]);
11209
+ return [4 /*yield*/, user_collection_1.Users.findById(contextUserId)];
11210
+ case 2:
11211
+ user = _d.sent();
11212
+ userClientId = normalizeOptionalString((_b = user === null || user === void 0 ? void 0 : user.other) === null || _b === void 0 ? void 0 : _b.id_client);
11213
+ if (userClientId) {
11214
+ return [2 /*return*/, userClientId];
11215
+ }
11216
+ return [3 /*break*/, 4];
11217
+ case 3:
11218
+ _a = _d.sent();
11219
+ return [3 /*break*/, 4];
11220
+ case 4:
11221
+ config = ((_c = resolveio_server_app_1.ResolveIOServer.getServerConfig) === null || _c === void 0 ? void 0 : _c.call(resolveio_server_app_1.ResolveIOServer)) || {};
11222
+ configClientId = normalizeOptionalString(config['CLIENT_ID'] || config['client_id'] || process.env.CLIENT_ID || '');
11223
+ if (configClientId) {
11224
+ return [2 /*return*/, configClientId];
11225
+ }
11226
+ return [2 /*return*/, explicitValue];
11227
+ }
11228
+ });
11229
+ });
11230
+ }
11231
+ function ensureConversation(input, mode, contextUserId) {
11232
+ return __awaiter(this, void 0, void 0, function () {
11233
+ var idConversation, existing, now, resolvedClientId, doc, result;
10936
11234
  return __generator(this, function (_a) {
10937
11235
  switch (_a.label) {
10938
11236
  case 0:
@@ -10947,8 +11245,11 @@ function ensureConversation(input, mode) {
10947
11245
  _a.label = 2;
10948
11246
  case 2:
10949
11247
  now = new Date();
11248
+ return [4 /*yield*/, resolveClientIdFromConfig(input.id_client, contextUserId)];
11249
+ case 3:
11250
+ resolvedClientId = _a.sent();
10950
11251
  doc = {
10951
- id_client: resolveClientIdFromConfig(input.id_client),
11252
+ id_client: resolvedClientId,
10952
11253
  id_app: normalizeOptionalString(input.id_app),
10953
11254
  title: 'New Conversation',
10954
11255
  mode: mode,
@@ -10960,7 +11261,7 @@ function ensureConversation(input, mode) {
10960
11261
  updatedAt: now
10961
11262
  };
10962
11263
  return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.insertOne(doc)];
10963
- case 3:
11264
+ case 4:
10964
11265
  result = _a.sent();
10965
11266
  return [2 /*return*/, result];
10966
11267
  }
@@ -11044,10 +11345,25 @@ function normalizeHistoryLimit(value) {
11044
11345
  }
11045
11346
  return Math.min(Math.max((0, common_1.round)(parsed), 0), 30);
11046
11347
  }
11047
- function resolveClientId(conversation, inputClientId) {
11048
- return normalizeOptionalString(inputClientId)
11049
- || normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client)
11050
- || resolveClientIdFromConfig();
11348
+ function resolveClientId(conversation, inputClientId, contextUserId) {
11349
+ return __awaiter(this, void 0, void 0, function () {
11350
+ var inputValue, conversationValue;
11351
+ return __generator(this, function (_a) {
11352
+ switch (_a.label) {
11353
+ case 0:
11354
+ inputValue = normalizeOptionalString(inputClientId);
11355
+ if (isLikelyObjectId(inputValue)) {
11356
+ return [2 /*return*/, inputValue];
11357
+ }
11358
+ conversationValue = normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client);
11359
+ if (isLikelyObjectId(conversationValue)) {
11360
+ return [2 /*return*/, conversationValue];
11361
+ }
11362
+ return [4 /*yield*/, resolveClientIdFromConfig(inputValue || conversationValue, contextUserId)];
11363
+ case 1: return [2 /*return*/, _a.sent()];
11364
+ }
11365
+ });
11366
+ });
11051
11367
  }
11052
11368
  function estimateUsage(messages, responseText, model) {
11053
11369
  var inputTokens = (0, tokenizer_1.countChatTokens)(messages, model);