@resolveio/server-lib 22.1.32 → 22.2.0

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.
@@ -162,7 +162,6 @@ var ai_terminal_message_collection_1 = require("../collections/ai-terminal-messa
162
162
  var ai_terminal_issue_report_collection_1 = require("../collections/ai-terminal-issue-report.collection");
163
163
  var common_1 = require("../util/common");
164
164
  var tokenizer_1 = require("../util/tokenizer");
165
- var openai_client_1 = require("../services/openai-client");
166
165
  var codex_client_1 = require("../services/codex-client");
167
166
  var openai_usage_ledger_manager_1 = require("../managers/openai-usage-ledger.manager");
168
167
  var DEFAULT_MAX_FILE_MB = 50;
@@ -172,6 +171,8 @@ var DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS = 40000;
172
171
  var DEFAULT_CODEX_MODEL = 'gpt-5.3-codex';
173
172
  var DEFAULT_CODEX_FALLBACK_MODEL = 'gpt-5.2-codex';
174
173
  var DEFAULT_CODEX_TIMEOUT_MS = 180000;
174
+ var DEFAULT_AI_ASSISTANT_RUN_BUDGET_MS = 60000;
175
+ var DEFAULT_AI_ASSISTANT_MONGO_MAX_TIME_MS = 8000;
175
176
  var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
176
177
  var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
177
178
  var AI_ASSISTANT_MONGO_EXPORT_MAX_LIMIT = 5000;
@@ -199,6 +200,8 @@ var AI_ASSISTANT_CURRENCY_CODE = 'USD';
199
200
  var AI_ASSISTANT_USD_CURRENCY_TEXT_PATTERN = /\b(?:USD|US\$)(?:\s| | |[\u00A0\u202F\u2007])*\$?\s*([-+]?[0-9][0-9,]*(?:\.[0-9]+)?)/gi;
200
201
  var AI_ASSISTANT_REVENUE_VERIFY_DIFF_WARN_THRESHOLD = 0.15;
201
202
  var AI_ASSISTANT_REVENUE_VERIFY_PAID_GRAND_GAP_WARN_THRESHOLD = 0.10;
203
+ var AI_ASSISTANT_CODEX_MIN_STAGE_BUDGET_MS = 1500;
204
+ var AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS = 80;
202
205
  var AI_ASSISTANT_DISPLAY_PRIORITY_FIELDS = [
203
206
  'name',
204
207
  'title',
@@ -552,7 +555,7 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
552
555
  '- Do not modify files, run destructive commands, or access databases directly.',
553
556
  '- Read-only data access is allowed only via the REPORT_BUILDER_READ/REPORT_BUILDER_AGG directives (see below).',
554
557
  '- Do not access secrets, credentials, or user data.',
555
- '- If asked about the underlying AI/model/provider/runtime (including Codex/OpenAI/local-vs-hosted/version details), refuse. This information is not available to users, including admins and super admins.',
558
+ '- If asked about the underlying AI/model/provider/runtime (including local-vs-hosted/version details), refuse. This information is not available to users, including admins and super admins.',
556
559
  '- If the user has a customer portal scope (other.id_customer), only discuss that customer\'s data and what is visible in their customer portal. Never reference other customers or internal/admin-only data. If asked for anything outside the portal, say it isn\'t available.',
557
560
  '- Do not assist with hacking, bypassing security, or abuse.',
558
561
  'Accuracy & tools:',
@@ -1306,7 +1309,7 @@ function loadAiTerminalMethods(methodManager) {
1306
1309
  }
1307
1310
  function executeAiTerminalRun(payload, context) {
1308
1311
  return __awaiter(this, void 0, void 0, function () {
1309
- var input, message, requestId, identityGuardrail, conversation_1, now_1, userMsg, assistantMsg, isSuperAdmin, guardrailsEnabled, guardrail, conversation_2, now_2, userMsg, assistantMsg, conversation, now, attachments, attachmentData, config, systemPrompt, userPromptTemplate, userPrompt, historyLimit, history, _a, messages, openaiSettings, client, response, usage, idClient, userDoc, assistantDoc, insertResult;
1312
+ var input, message, requestId, identityGuardrail, conversation_1, now_1, userMsg, assistantMsg, isSuperAdmin, guardrailsEnabled, guardrail, conversation_2, now_2, userMsg, assistantMsg, conversation, now, attachments, attachmentData, config, systemPrompt, userPromptTemplate, userPrompt, historyLimit, history, _a, messages, codexModel, codexFallbackModels, codexSettings, client, responseText, usage, idClient, userDoc, assistantDoc, insertResult;
1310
1313
  return __generator(this, function (_b) {
1311
1314
  switch (_b.label) {
1312
1315
  case 0:
@@ -1321,7 +1324,7 @@ function executeAiTerminalRun(payload, context) {
1321
1324
  requestId = normalizeOptionalString(input.request_id);
1322
1325
  identityGuardrail = evaluateAssistantIdentityDisclosureGuardrail(message);
1323
1326
  if (!(identityGuardrail === null || identityGuardrail === void 0 ? void 0 : identityGuardrail.blocked)) return [3 /*break*/, 5];
1324
- return [4 /*yield*/, ensureConversation(input, 'openai', context === null || context === void 0 ? void 0 : context.id_user)];
1327
+ return [4 /*yield*/, ensureConversation(input, 'codex', context === null || context === void 0 ? void 0 : context.id_user)];
1325
1328
  case 1:
1326
1329
  conversation_1 = _b.sent();
1327
1330
  now_1 = new Date();
@@ -1362,7 +1365,7 @@ function executeAiTerminalRun(payload, context) {
1362
1365
  if (!guardrailsEnabled) return [3 /*break*/, 11];
1363
1366
  guardrail = evaluateGuardrails(message);
1364
1367
  if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 11];
1365
- return [4 /*yield*/, ensureConversation(input, 'openai', context === null || context === void 0 ? void 0 : context.id_user)];
1368
+ return [4 /*yield*/, ensureConversation(input, 'codex', context === null || context === void 0 ? void 0 : context.id_user)];
1366
1369
  case 7:
1367
1370
  conversation_2 = _b.sent();
1368
1371
  now_2 = new Date();
@@ -1396,7 +1399,7 @@ function executeAiTerminalRun(payload, context) {
1396
1399
  message: assistantMsg,
1397
1400
  guardrails: { blocked: true, reason: guardrail.reason }
1398
1401
  }];
1399
- case 11: return [4 /*yield*/, ensureConversation(input, 'openai', context === null || context === void 0 ? void 0 : context.id_user)];
1402
+ case 11: return [4 /*yield*/, ensureConversation(input, 'codex', context === null || context === void 0 ? void 0 : context.id_user)];
1400
1403
  case 12:
1401
1404
  conversation = _b.sent();
1402
1405
  now = new Date();
@@ -1433,19 +1436,32 @@ function executeAiTerminalRun(payload, context) {
1433
1436
  if (userPrompt) {
1434
1437
  messages.push({ role: 'user', content: userPrompt });
1435
1438
  }
1436
- openaiSettings = resolveOpenAISettings(config);
1437
- client = new openai_client_1.OpenAIClient(openaiSettings);
1438
- return [4 /*yield*/, client.chat(messages, { timeoutMs: 60000, responseFormat: config.response_format })];
1439
+ codexModel = resolveCodexModel(config);
1440
+ codexFallbackModels = resolveCodexFallbackModels(config, codexModel);
1441
+ codexSettings = resolveCodexSettings({ model: codexModel, fallbackModels: codexFallbackModels });
1442
+ client = getAssistantCodexClient(codexSettings);
1443
+ return [4 /*yield*/, client.run(buildCodexChatPrompt(messages), {
1444
+ timeoutMs: 60000,
1445
+ threadOptions: {
1446
+ model: codexModel,
1447
+ sandboxMode: 'read-only',
1448
+ skipGitRepoCheck: true,
1449
+ networkAccessEnabled: false,
1450
+ webSearchMode: 'disabled',
1451
+ webSearchEnabled: false,
1452
+ approvalPolicy: 'never'
1453
+ }
1454
+ })];
1439
1455
  case 17:
1440
- response = _b.sent();
1441
- usage = response.usage || estimateUsage(messages, response.content, openaiSettings.model);
1456
+ responseText = _b.sent();
1457
+ usage = estimateUsage(messages, responseText, codexModel);
1442
1458
  return [4 /*yield*/, resolveClientId(conversation, input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1443
1459
  case 18:
1444
1460
  idClient = _b.sent();
1445
1461
  if (!idClient) return [3 /*break*/, 20];
1446
1462
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1447
1463
  id_client: idClient,
1448
- model: response.model || openaiSettings.model || 'unknown',
1464
+ model: codexModel || 'unknown',
1449
1465
  input_tokens: usage.inputTokens,
1450
1466
  output_tokens: usage.outputTokens,
1451
1467
  total_tokens: usage.totalTokens,
@@ -1468,10 +1484,10 @@ function executeAiTerminalRun(payload, context) {
1468
1484
  assistantDoc = {
1469
1485
  id_conversation: conversation._id,
1470
1486
  role: 'assistant',
1471
- content: response.content,
1487
+ content: responseText,
1472
1488
  metadata: input.request_id ? { request_id: input.request_id } : undefined,
1473
1489
  usage: {
1474
- model: response.model || openaiSettings.model,
1490
+ model: codexModel,
1475
1491
  input_tokens: usage.inputTokens,
1476
1492
  output_tokens: usage.outputTokens,
1477
1493
  total_tokens: usage.totalTokens
@@ -1504,7 +1520,7 @@ function executeAiTerminalRun(payload, context) {
1504
1520
  }
1505
1521
  function executeAiFormPatch(payload, context) {
1506
1522
  return __awaiter(this, void 0, void 0, function () {
1507
- var input, message, allowedFields, guardrail, systemPrompt, userPrompt, messages, openaiSettings, client, response, usage, idClient, parsed;
1523
+ var input, message, allowedFields, guardrail, systemPrompt, userPrompt, messages, config, codexModel, codexFallbackModels, codexSettings, client, responseText, usage, idClient, parsed;
1508
1524
  var _a;
1509
1525
  return __generator(this, function (_b) {
1510
1526
  switch (_b.label) {
@@ -1531,19 +1547,33 @@ function executeAiFormPatch(payload, context) {
1531
1547
  { role: 'system', content: systemPrompt },
1532
1548
  { role: 'user', content: userPrompt }
1533
1549
  ];
1534
- openaiSettings = resolveOpenAISettings(input.config || {});
1535
- client = new openai_client_1.OpenAIClient(openaiSettings);
1536
- return [4 /*yield*/, client.chat(messages, { timeoutMs: 60000, responseFormat: 'json_object' })];
1550
+ config = sanitizeConfig(input.config || {});
1551
+ codexModel = resolveCodexModel(config);
1552
+ codexFallbackModels = resolveCodexFallbackModels(config, codexModel);
1553
+ codexSettings = resolveCodexSettings({ model: codexModel, fallbackModels: codexFallbackModels });
1554
+ client = getAssistantCodexClient(codexSettings);
1555
+ return [4 /*yield*/, client.run(buildCodexChatPrompt(messages), {
1556
+ timeoutMs: 60000,
1557
+ threadOptions: {
1558
+ model: codexModel,
1559
+ sandboxMode: 'read-only',
1560
+ skipGitRepoCheck: true,
1561
+ networkAccessEnabled: false,
1562
+ webSearchMode: 'disabled',
1563
+ webSearchEnabled: false,
1564
+ approvalPolicy: 'never'
1565
+ }
1566
+ })];
1537
1567
  case 1:
1538
- response = _b.sent();
1539
- usage = response.usage || estimateUsage(messages, response.content, response.model || openaiSettings.model);
1568
+ responseText = _b.sent();
1569
+ usage = estimateUsage(messages, responseText, codexModel);
1540
1570
  return [4 /*yield*/, resolveClientIdFromConfig(input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
1541
1571
  case 2:
1542
1572
  idClient = _b.sent();
1543
1573
  if (!idClient) return [3 /*break*/, 4];
1544
1574
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
1545
1575
  id_client: idClient,
1546
- model: response.model || openaiSettings.model || 'unknown',
1576
+ model: codexModel || 'unknown',
1547
1577
  input_tokens: usage.inputTokens,
1548
1578
  output_tokens: usage.outputTokens,
1549
1579
  total_tokens: usage.totalTokens,
@@ -1553,7 +1583,7 @@ function executeAiFormPatch(payload, context) {
1553
1583
  _b.sent();
1554
1584
  _b.label = 4;
1555
1585
  case 4:
1556
- parsed = parseJsonObject(response.content);
1586
+ parsed = parseJsonObject(responseText);
1557
1587
  if (!parsed || typeof parsed !== 'object') {
1558
1588
  throw new Error('AI form patch response was not valid JSON.');
1559
1589
  }
@@ -1561,7 +1591,7 @@ function executeAiFormPatch(payload, context) {
1561
1591
  patch: (_a = parsed.patch) !== null && _a !== void 0 ? _a : parsed,
1562
1592
  notes: normalizeOptionalString(parsed.notes) || undefined,
1563
1593
  usage: {
1564
- model: response.model || openaiSettings.model,
1594
+ model: codexModel,
1565
1595
  input_tokens: usage.inputTokens,
1566
1596
  output_tokens: usage.outputTokens,
1567
1597
  total_tokens: usage.totalTokens
@@ -1781,18 +1811,23 @@ function executeAiAssistantCodexRun(payload, context) {
1781
1811
  insertResult = _d.sent();
1782
1812
  assistantMessageId = (insertResult === null || insertResult === void 0 ? void 0 : insertResult._id) || (insertResult === null || insertResult === void 0 ? void 0 : insertResult.insertedId);
1783
1813
  enqueueAssistantCodexRun(function () { return __awaiter(_this, void 0, void 0, function () {
1784
- var runStart, steps, recordStep, progressTracker, streamProgress, assistantContent, toolResult, assistantDebug, directiveSource, requestClassification, dataQuestion, lastDirective, heuristicDirectivePrecomputed, usedDeterministicHeuristicFastPath, requestedTimeGrain, requestedBreakdownDimensions, enforceDatedDirective, enforceGroupedDirective, datedDirectiveRetryUsed, datedDirectiveResolved, toolResponseDebug, toolError, termHints, collectionHints, fieldHints, methodHints, publicationHints, collectionTokenization, collectionRanking, collectionSelection, collectionOverride, collectionNames, plannerEnabled, plannerUsed, plannerSkipReason, plannerOutput, plannerRaw, timingBreakdown, codexUsage, accumulateCodexUsage, contextRoute, contextMode, hintSeed, termExpansion, hintText, baseTokens, expandedTokens, baseWeights, expandedWeights, dbName, db, surfaceHints, _a, allowedRoutes, rankedAllowedRoutes, routeHints, rankedCollectionHints, rankedCollections, hintCollections, assistantContext, hasDeterministicHeuristicFastPath, prompt_1, workspaceRoot, codexConfig, runOptions, plannerRunOptions, shouldRunPlanner, plannerPrompt, plannerStart, _b, preferListDirective, directiveStyleHint, directivePromptMode, responseText, directiveText, directive, heuristicDirectiveFastPath, directivePrompt, directiveStart, forcedDirective, _c, initialStart, extractedDirective, error_2, directivePrompt, forcedStart, forcedDirective, _d, strictDirectivePrompt, strictStart, strictDirectiveText, strictDirective, strictDirectiveIsDated, shouldUseStrictDirective, _e, guardDirectivePrompt, guardStart, guardDirectiveText, guardDirective, _f, groupedDirectivePrompt, groupedStart, groupedDirectiveText, groupedDirective, _g, heuristicDirective, requestedCollection, allowCollectionOverride, cleanedResponseText, deniedModuleByIntent, permissionLabel, effectiveDirective, toolRequest, toolStart, toolResponse, _h, toolPayload, skipFollowupCodex, followupPrompt, followupStart, followupText, _j, error_3, error_4, finishedAt, finalNow, finishedAt, codexMs, draftingMs, finalMetadata, finalUsage, usageClientId, usageError_1, finalAssistantDoc, setPayload, finalizeError_1, failedAt, fallbackContent, failureMetadata, persistError_1, _k;
1814
+ var runStart, fastModeEnabled, runBudgetMs, runDeadlineMs, steps, recordStep, progressTracker, streamProgress, remainingRunBudgetMs, hasRunBudget, applyCodexStageBudget, assistantContent, toolResult, assistantDebug, directiveSource, requestClassification, dataQuestion, lastDirective, heuristicDirectivePrecomputed, usedDeterministicHeuristicFastPath, requestedTimeGrain, requestedBreakdownDimensions, enforceDatedDirective, enforceGroupedDirective, datedDirectiveRetryUsed, datedDirectiveResolved, toolResponseDebug, toolError, termHints, collectionHints, fieldHints, methodHints, publicationHints, collectionTokenization, collectionRanking, collectionSelection, collectionOverride, collectionNames, plannerEnabled, plannerUsed, plannerSkipReason, plannerOutput, plannerRaw, timingBreakdown, codexUsage, accumulateCodexUsage, contextRoute, contextMode, hintSeed, termExpansion, hintText, baseTokens, expandedTokens, baseWeights, expandedWeights, dbName, db, surfaceHints, _a, allowedRoutes, rankedAllowedRoutes, routeHints, rankedCollectionHints, rankedCollections, hintCollections, assistantContext, hasDeterministicHeuristicFastPath, prompt_1, workspaceRoot, codexConfig, runOptions, plannerRunOptions, shouldRunPlanner, plannerBudgetAvailable, plannerPrompt, plannerStart, _b, preferListDirective, directiveStyleHint, directivePromptMode, responseText, directiveText, directive, heuristicDirectiveFastPath, directivePrompt, directiveStart, forcedDirective, _c, initialStart, extractedDirective, error_2, directivePrompt, forcedStart, forcedDirective, _d, strictDirectivePrompt, strictStart, strictDirectiveText, strictDirective, strictDirectiveIsDated, shouldUseStrictDirective, _e, guardDirectivePrompt, guardStart, guardDirectiveText, guardDirective, _f, groupedDirectivePrompt, groupedStart, groupedDirectiveText, groupedDirective, _g, heuristicDirective, requestedCollection, allowCollectionOverride, cleanedResponseText, deniedModuleByIntent, permissionLabel, effectiveDirective, toolRequest, toolStart, toolResponse, _h, toolPayload, zeroRowResult, skipFollowupCodex, followupPrompt, followupStart, followupText, _j, error_3, error_4, runBudgetExceeded, finishedAt, finalNow, finishedAt, codexMs, draftingMs, finalMetadata, finalUsage, usageClientId, usageError_1, finalAssistantDoc, setPayload, finalizeError_1, failedAt, fallbackContent, failureMetadata, persistError_1, _k;
1785
1815
  var _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13;
1786
1816
  return __generator(this, function (_14) {
1787
1817
  switch (_14.label) {
1788
1818
  case 0:
1789
1819
  runStart = Date.now();
1820
+ fastModeEnabled = resolveAssistantFastModeEnabled();
1821
+ runBudgetMs = resolveAssistantRunBudgetMs();
1822
+ runDeadlineMs = fastModeEnabled ? runStart + runBudgetMs : null;
1790
1823
  if (aiWorkerDebug) {
1791
1824
  console.log(new Date(), '[AI Worker Debug] codex run start', {
1792
1825
  requestId: requestId || null,
1793
1826
  id_user: (context === null || context === void 0 ? void 0 : context.id_user) || null,
1794
1827
  id_conversation: (conversation === null || conversation === void 0 ? void 0 : conversation._id) || null,
1795
1828
  id_message: assistantMessageId ? String(assistantMessageId) : null,
1829
+ fastModeEnabled: fastModeEnabled,
1830
+ runBudgetMs: runDeadlineMs ? runBudgetMs : null,
1796
1831
  isWorkerInstance: process.env.IS_WORKER_INSTANCE || null,
1797
1832
  workerIndex: process.env.WORKER_INDEX || null,
1798
1833
  workerInstance: process.env.NODE_APP_INSTANCE || null
@@ -1809,6 +1844,36 @@ function executeAiAssistantCodexRun(payload, context) {
1809
1844
  };
1810
1845
  progressTracker = createAssistantProgressTracker(assistantMessageId, initialProgress);
1811
1846
  streamProgress = createAssistantStreamProgressHandler(progressTracker);
1847
+ remainingRunBudgetMs = function () {
1848
+ if (!runDeadlineMs) {
1849
+ return null;
1850
+ }
1851
+ return Math.max(runDeadlineMs - Date.now(), 0);
1852
+ };
1853
+ hasRunBudget = function (phase, minMs) {
1854
+ if (minMs === void 0) { minMs = AI_ASSISTANT_CODEX_MIN_STAGE_BUDGET_MS; }
1855
+ var remaining = remainingRunBudgetMs();
1856
+ if (remaining === null || remaining >= minMs) {
1857
+ return true;
1858
+ }
1859
+ recordStep("".concat(phase, ": skipped"), {
1860
+ reason: 'run_budget_exhausted',
1861
+ remainingMs: remaining,
1862
+ budgetMs: runBudgetMs
1863
+ });
1864
+ return false;
1865
+ };
1866
+ applyCodexStageBudget = function (base) {
1867
+ var remaining = remainingRunBudgetMs();
1868
+ if (remaining === null) {
1869
+ return base;
1870
+ }
1871
+ var baseTimeout = typeof base.timeoutMs === 'number' && base.timeoutMs > 0
1872
+ ? base.timeoutMs
1873
+ : resolveCodexTimeoutMs();
1874
+ var timeoutMs = Math.max(1000, Math.min(baseTimeout, remaining));
1875
+ return __assign(__assign({}, base), { timeoutMs: timeoutMs });
1876
+ };
1812
1877
  assistantContent = '';
1813
1878
  toolResult = null;
1814
1879
  assistantDebug = null;
@@ -1879,7 +1944,7 @@ function executeAiAssistantCodexRun(payload, context) {
1879
1944
  });
1880
1945
  _14.label = 1;
1881
1946
  case 1:
1882
- _14.trys.push([1, 53, 54, 55]);
1947
+ _14.trys.push([1, 56, 57, 58]);
1883
1948
  hintSeed = [message, contextRoute].filter(Boolean).join(' ');
1884
1949
  termExpansion = expandAssistantTermSynonyms(hintSeed);
1885
1950
  hintText = termExpansion.expanded || hintSeed;
@@ -2022,7 +2087,8 @@ function executeAiAssistantCodexRun(payload, context) {
2022
2087
  requestClassification: requestClassification,
2023
2088
  hasDeterministicHeuristicFastPath: hasDeterministicHeuristicFastPath
2024
2089
  });
2025
- if (!shouldRunPlanner) return [3 /*break*/, 12];
2090
+ plannerBudgetAvailable = !shouldRunPlanner || hasRunBudget('Planning: planner');
2091
+ if (!(shouldRunPlanner && plannerBudgetAvailable)) return [3 /*break*/, 12];
2026
2092
  plannerUsed = true;
2027
2093
  recordStep('Planning: planner prompt');
2028
2094
  plannerPrompt = buildAssistantPlannerPrompt({
@@ -2041,7 +2107,7 @@ function executeAiAssistantCodexRun(payload, context) {
2041
2107
  case 8:
2042
2108
  _14.trys.push([8, 10, , 11]);
2043
2109
  plannerStart = Date.now();
2044
- return [4 /*yield*/, runCodexInWorkerThread(plannerPrompt, plannerRunOptions, codexConfig, streamProgress)];
2110
+ return [4 /*yield*/, runCodexInWorkerThread(plannerPrompt, applyCodexStageBudget(plannerRunOptions), codexConfig, streamProgress)];
2045
2111
  case 9:
2046
2112
  plannerRaw = _14.sent();
2047
2113
  accumulateCodexUsage(plannerPrompt, plannerRaw);
@@ -2062,6 +2128,9 @@ function executeAiAssistantCodexRun(payload, context) {
2062
2128
  else if (!requestClassification.dataQuestion) {
2063
2129
  plannerSkipReason = "non_data_".concat(requestClassification.type || 'unknown');
2064
2130
  }
2131
+ else if (!plannerBudgetAvailable) {
2132
+ plannerSkipReason = 'run_budget_exhausted';
2133
+ }
2065
2134
  else {
2066
2135
  plannerSkipReason = 'policy';
2067
2136
  }
@@ -2122,11 +2191,12 @@ function executeAiAssistantCodexRun(payload, context) {
2122
2191
  if (!(dataQuestion && !directive)) return [3 /*break*/, 17];
2123
2192
  recordStep('Directive: determine tool', { type: 'data-question' });
2124
2193
  directivePrompt = buildAssistantCodexDirectivePrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, directiveStyleHint, directivePromptMode);
2194
+ if (!hasRunBudget('Directive: determine tool')) return [3 /*break*/, 17];
2125
2195
  _14.label = 14;
2126
2196
  case 14:
2127
2197
  _14.trys.push([14, 16, , 17]);
2128
2198
  directiveStart = Date.now();
2129
- return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, runOptions, codexConfig, streamProgress)];
2199
+ return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2130
2200
  case 15:
2131
2201
  directiveText = _14.sent();
2132
2202
  accumulateCodexUsage(directivePrompt, directiveText);
@@ -2151,11 +2221,12 @@ function executeAiAssistantCodexRun(payload, context) {
2151
2221
  case 17:
2152
2222
  if (!(!directive && !dataQuestion)) return [3 /*break*/, 21];
2153
2223
  recordStep('Response: draft initial answer', { mode: 'full' });
2224
+ if (!hasRunBudget('Response: initial draft')) return [3 /*break*/, 21];
2154
2225
  _14.label = 18;
2155
2226
  case 18:
2156
2227
  _14.trys.push([18, 20, , 21]);
2157
2228
  initialStart = Date.now();
2158
- return [4 /*yield*/, runCodexInWorkerThread(prompt_1, runOptions, codexConfig, streamProgress)];
2229
+ return [4 /*yield*/, runCodexInWorkerThread(prompt_1, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2159
2230
  case 19:
2160
2231
  responseText = _14.sent();
2161
2232
  accumulateCodexUsage(prompt_1, responseText);
@@ -2184,11 +2255,12 @@ function executeAiAssistantCodexRun(payload, context) {
2184
2255
  if (!(!directive && dataQuestion)) return [3 /*break*/, 25];
2185
2256
  recordStep('Directive: forced retry', { mode: 'directive-only' });
2186
2257
  directivePrompt = buildAssistantCodexDirectivePrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, directiveStyleHint, directivePromptMode);
2258
+ if (!hasRunBudget('Directive: forced retry')) return [3 /*break*/, 25];
2187
2259
  _14.label = 22;
2188
2260
  case 22:
2189
2261
  _14.trys.push([22, 24, , 25]);
2190
2262
  forcedStart = Date.now();
2191
- return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, runOptions, codexConfig, streamProgress)];
2263
+ return [4 /*yield*/, runCodexInWorkerThread(directivePrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2192
2264
  case 23:
2193
2265
  directiveText = _14.sent();
2194
2266
  accumulateCodexUsage(directivePrompt, directiveText);
@@ -2226,11 +2298,12 @@ function executeAiAssistantCodexRun(payload, context) {
2226
2298
  requestedBreakdowns: requestedBreakdownDimensions,
2227
2299
  strict: true
2228
2300
  }), 'aggregate_only');
2301
+ if (!hasRunBudget('Directive: dated retry')) return [3 /*break*/, 29];
2229
2302
  _14.label = 26;
2230
2303
  case 26:
2231
2304
  _14.trys.push([26, 28, , 29]);
2232
2305
  strictStart = Date.now();
2233
- return [4 /*yield*/, runCodexInWorkerThread(strictDirectivePrompt, runOptions, codexConfig, streamProgress)];
2306
+ return [4 /*yield*/, runCodexInWorkerThread(strictDirectivePrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2234
2307
  case 27:
2235
2308
  strictDirectiveText = _14.sent();
2236
2309
  accumulateCodexUsage(strictDirectivePrompt, strictDirectiveText);
@@ -2273,11 +2346,12 @@ function executeAiAssistantCodexRun(payload, context) {
2273
2346
  requestedBreakdowns: requestedBreakdownDimensions,
2274
2347
  strict: true
2275
2348
  }), 'aggregate_only');
2349
+ if (!hasRunBudget('Directive: dated guard retry')) return [3 /*break*/, 33];
2276
2350
  _14.label = 30;
2277
2351
  case 30:
2278
2352
  _14.trys.push([30, 32, , 33]);
2279
2353
  guardStart = Date.now();
2280
- return [4 /*yield*/, runCodexInWorkerThread(guardDirectivePrompt, runOptions, codexConfig, streamProgress)];
2354
+ return [4 /*yield*/, runCodexInWorkerThread(guardDirectivePrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2281
2355
  case 31:
2282
2356
  guardDirectiveText = _14.sent();
2283
2357
  accumulateCodexUsage(guardDirectivePrompt, guardDirectiveText);
@@ -2318,11 +2392,12 @@ function executeAiAssistantCodexRun(payload, context) {
2318
2392
  requestedBreakdowns: requestedBreakdownDimensions,
2319
2393
  strict: true
2320
2394
  }), 'aggregate_only');
2395
+ if (!hasRunBudget('Directive: grouped guard retry')) return [3 /*break*/, 37];
2321
2396
  _14.label = 34;
2322
2397
  case 34:
2323
2398
  _14.trys.push([34, 36, , 37]);
2324
2399
  groupedStart = Date.now();
2325
- return [4 /*yield*/, runCodexInWorkerThread(groupedDirectivePrompt, runOptions, codexConfig, streamProgress)];
2400
+ return [4 /*yield*/, runCodexInWorkerThread(groupedDirectivePrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2326
2401
  case 35:
2327
2402
  groupedDirectiveText = _14.sent();
2328
2403
  accumulateCodexUsage(groupedDirectivePrompt, groupedDirectiveText);
@@ -2405,12 +2480,17 @@ function executeAiAssistantCodexRun(payload, context) {
2405
2480
  });
2406
2481
  assistantContent = "I couldn't run that request because this account does not have ".concat(permissionLabel, " permission.");
2407
2482
  toolError = new Error('AI assistant report builder bridge: Access denied.');
2408
- return [3 /*break*/, 52];
2483
+ return [3 /*break*/, 55];
2409
2484
  case 38:
2410
- if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 51];
2485
+ if (!((directive === null || directive === void 0 ? void 0 : directive.payload) && AI_ASSISTANT_TOOL_MAX_STEPS > 0)) return [3 /*break*/, 54];
2411
2486
  effectiveDirective = collectionOverride
2412
2487
  ? __assign(__assign({}, directive), { payload: __assign(__assign({}, (directive.payload || {})), { collection: collectionOverride.to }) }) : directive;
2413
2488
  toolRequest = buildAssistantToolRequest(effectiveDirective, input);
2489
+ toolRequest.__assistantRuntime = {
2490
+ fastMode: fastModeEnabled,
2491
+ deadlineMs: runDeadlineMs || undefined,
2492
+ maxTimeMS: resolveAssistantMongoDefaultMaxTimeMs()
2493
+ };
2414
2494
  progressTracker.push('Grabbing Data');
2415
2495
  recordStep('Grabbing Data: start', {
2416
2496
  type: effectiveDirective.type,
@@ -2419,18 +2499,22 @@ function executeAiAssistantCodexRun(payload, context) {
2419
2499
  });
2420
2500
  _14.label = 39;
2421
2501
  case 39:
2422
- _14.trys.push([39, 49, , 50]);
2502
+ _14.trys.push([39, 52, , 53]);
2503
+ if (!!hasRunBudget('Grabbing Data', AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS)) return [3 /*break*/, 40];
2504
+ assistantContent = buildAssistantRunBudgetExceededMessage();
2505
+ return [3 /*break*/, 51];
2506
+ case 40:
2423
2507
  toolStart = Date.now();
2424
- if (!(effectiveDirective.type === 'aggregate')) return [3 /*break*/, 41];
2508
+ if (!(effectiveDirective.type === 'aggregate')) return [3 /*break*/, 42];
2425
2509
  return [4 /*yield*/, executeAiAssistantReportBuilderAggregate(toolRequest, context)];
2426
- case 40:
2427
- _h = _14.sent();
2428
- return [3 /*break*/, 43];
2429
- case 41: return [4 /*yield*/, executeAiAssistantReportBuilderRead(toolRequest, context)];
2430
- case 42:
2510
+ case 41:
2431
2511
  _h = _14.sent();
2432
- _14.label = 43;
2512
+ return [3 /*break*/, 44];
2513
+ case 42: return [4 /*yield*/, executeAiAssistantReportBuilderRead(toolRequest, context)];
2433
2514
  case 43:
2515
+ _h = _14.sent();
2516
+ _14.label = 44;
2517
+ case 44:
2434
2518
  toolResponse = _h;
2435
2519
  timingBreakdown.toolMs = Date.now() - toolStart;
2436
2520
  toolResponseDebug = (toolResponse === null || toolResponse === void 0 ? void 0 : toolResponse.debug) && typeof toolResponse.debug === 'object'
@@ -2444,58 +2528,71 @@ function executeAiAssistantCodexRun(payload, context) {
2444
2528
  columns: toolPayload.result.output.columns
2445
2529
  });
2446
2530
  progressTracker.push('Drafting response');
2531
+ zeroRowResult = toolPayload.result.output.rowCount <= 0;
2447
2532
  skipFollowupCodex = usedDeterministicHeuristicFastPath
2448
- || isAssistantDeterministicHeuristicDirective(effectiveDirective);
2449
- if (!skipFollowupCodex) return [3 /*break*/, 44];
2533
+ || isAssistantDeterministicHeuristicDirective(effectiveDirective)
2534
+ || zeroRowResult;
2535
+ if (!skipFollowupCodex) return [3 /*break*/, 45];
2450
2536
  recordStep('Drafting response: deterministic summary', {
2451
- reason: normalizeOptionalString(effectiveDirective.rawLine) || 'deterministic_heuristic'
2537
+ reason: zeroRowResult
2538
+ ? 'zero_rows'
2539
+ : (normalizeOptionalString(effectiveDirective.rawLine) || 'deterministic_heuristic')
2452
2540
  });
2453
2541
  assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
2454
2542
  assistantContent = applyAssistantDisplayTableToResponse(assistantContent, toolPayload.result.output.display);
2455
- return [3 /*break*/, 48];
2456
- case 44:
2543
+ return [3 /*break*/, 51];
2544
+ case 45:
2457
2545
  recordStep('Drafting response');
2458
2546
  followupPrompt = buildAssistantCodexToolFollowupPrompt(message, attachmentData.promptText, historyLines.join('\n'), assistantContext, toolPayload.prompt);
2459
- _14.label = 45;
2460
- case 45:
2461
- _14.trys.push([45, 47, , 48]);
2462
- followupStart = Date.now();
2463
- return [4 /*yield*/, runCodexInWorkerThread(followupPrompt, runOptions, codexConfig, streamProgress)];
2547
+ if (!hasRunBudget('Drafting response: followup')) return [3 /*break*/, 50];
2548
+ _14.label = 46;
2464
2549
  case 46:
2550
+ _14.trys.push([46, 48, , 49]);
2551
+ followupStart = Date.now();
2552
+ return [4 /*yield*/, runCodexInWorkerThread(followupPrompt, applyCodexStageBudget(runOptions), codexConfig, streamProgress)];
2553
+ case 47:
2465
2554
  followupText = _14.sent();
2466
2555
  accumulateCodexUsage(followupPrompt, followupText);
2467
2556
  timingBreakdown.followupMs = Date.now() - followupStart;
2468
2557
  assistantContent = sanitizeAssistantResponse(followupText);
2469
2558
  assistantContent = applyAssistantDisplayTableToResponse(assistantContent, toolPayload.result.output.display);
2470
- return [3 /*break*/, 48];
2471
- case 47:
2559
+ return [3 /*break*/, 49];
2560
+ case 48:
2472
2561
  _j = _14.sent();
2473
2562
  assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
2474
2563
  assistantContent = applyAssistantDisplayTableToResponse(assistantContent, toolPayload.result.output.display);
2475
- return [3 /*break*/, 48];
2476
- case 48: return [3 /*break*/, 50];
2477
- case 49:
2564
+ return [3 /*break*/, 49];
2565
+ case 49: return [3 /*break*/, 51];
2566
+ case 50:
2567
+ assistantContent = buildAssistantToolFallbackResponse(toolPayload.result);
2568
+ assistantContent = applyAssistantDisplayTableToResponse(assistantContent, toolPayload.result.output.display);
2569
+ _14.label = 51;
2570
+ case 51: return [3 /*break*/, 53];
2571
+ case 52:
2478
2572
  error_3 = _14.sent();
2479
2573
  assistantContent = buildAssistantToolErrorMessage(error_3);
2480
2574
  toolError = error_3;
2481
- return [3 /*break*/, 50];
2482
- case 50: return [3 /*break*/, 52];
2483
- case 51:
2575
+ return [3 /*break*/, 53];
2576
+ case 53: return [3 /*break*/, 55];
2577
+ case 54:
2484
2578
  progressTracker.push('Drafting response');
2485
2579
  recordStep('Drafting response');
2486
- _14.label = 52;
2487
- case 52: return [3 /*break*/, 55];
2488
- case 53:
2580
+ _14.label = 55;
2581
+ case 55: return [3 /*break*/, 58];
2582
+ case 56:
2489
2583
  error_4 = _14.sent();
2490
2584
  assistantContent = buildAssistantCodexErrorMessage(error_4);
2491
2585
  recordStep('Error', { message: normalizeOptionalString(error_4 === null || error_4 === void 0 ? void 0 : error_4.message) || 'Unknown error' });
2492
- return [3 /*break*/, 55];
2493
- case 54:
2586
+ return [3 /*break*/, 58];
2587
+ case 57:
2494
2588
  progressTracker.stop();
2495
2589
  return [7 /*endfinally*/];
2496
- case 55:
2590
+ case 58:
2591
+ runBudgetExceeded = runDeadlineMs ? Date.now() > runDeadlineMs : false;
2497
2592
  if (!assistantContent) {
2498
- assistantContent = buildAssistantCodexErrorMessage(null);
2593
+ assistantContent = runBudgetExceeded
2594
+ ? buildAssistantRunBudgetExceededMessage()
2595
+ : buildAssistantCodexErrorMessage(null);
2499
2596
  }
2500
2597
  assistantContent = applyAssistantVerificationNotes(assistantContent, toolResult);
2501
2598
  assistantContent = applyAssistantDatedReportWindow(assistantContent, toolResult);
@@ -2511,15 +2608,17 @@ function executeAiAssistantCodexRun(payload, context) {
2511
2608
  contentChars: assistantContent.length,
2512
2609
  totalMs: finishedAt - runStart,
2513
2610
  timingBreakdown: timingBreakdown,
2611
+ runBudgetMs: runDeadlineMs ? runBudgetMs : null,
2612
+ runBudgetRemainingMs: remainingRunBudgetMs(),
2514
2613
  isWorkerInstance: process.env.IS_WORKER_INSTANCE || null,
2515
2614
  workerIndex: process.env.WORKER_INDEX || null,
2516
2615
  workerInstance: process.env.NODE_APP_INSTANCE || null
2517
2616
  });
2518
2617
  }
2519
2618
  finalNow = new Date();
2520
- _14.label = 56;
2521
- case 56:
2522
- _14.trys.push([56, 67, , 78]);
2619
+ _14.label = 59;
2620
+ case 59:
2621
+ _14.trys.push([59, 70, , 81]);
2523
2622
  if (canViewDebug) {
2524
2623
  finishedAt = Date.now();
2525
2624
  codexMs = timingBreakdown.directiveMs
@@ -2587,7 +2686,11 @@ function executeAiAssistantCodexRun(payload, context) {
2587
2686
  }
2588
2687
  });
2589
2688
  }
2590
- finalMetadata = __assign(__assign(__assign(__assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), { pending: false }), (changeHistoryFastPathBypassedReason ? {
2689
+ finalMetadata = __assign(__assign(__assign(__assign(__assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), { pending: false }), (fastModeEnabled ? {
2690
+ fast_mode: true,
2691
+ run_budget_ms: runBudgetMs,
2692
+ run_budget_exhausted: runBudgetExceeded
2693
+ } : {})), (changeHistoryFastPathBypassedReason ? {
2591
2694
  fast_path_change_history_bypassed_reason: changeHistoryFastPathBypassedReason
2592
2695
  } : {})), (toolResult ? { tool_result: toolResult } : {})), (assistantDebug ? { debug: assistantDebug } : {}));
2593
2696
  finalUsage = codexUsage.total_tokens > 0 ? {
@@ -2596,14 +2699,14 @@ function executeAiAssistantCodexRun(payload, context) {
2596
2699
  output_tokens: codexUsage.output_tokens,
2597
2700
  total_tokens: codexUsage.total_tokens
2598
2701
  } : null;
2599
- if (!finalUsage) return [3 /*break*/, 61];
2702
+ if (!finalUsage) return [3 /*break*/, 64];
2600
2703
  return [4 /*yield*/, resolveClientId(conversation, input.id_client, context === null || context === void 0 ? void 0 : context.id_user)];
2601
- case 57:
2704
+ case 60:
2602
2705
  usageClientId = _14.sent();
2603
- if (!usageClientId) return [3 /*break*/, 61];
2604
- _14.label = 58;
2605
- case 58:
2606
- _14.trys.push([58, 60, , 61]);
2706
+ if (!usageClientId) return [3 /*break*/, 64];
2707
+ _14.label = 61;
2708
+ case 61:
2709
+ _14.trys.push([61, 63, , 64]);
2607
2710
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
2608
2711
  id_client: usageClientId,
2609
2712
  model: finalUsage.model,
@@ -2614,16 +2717,16 @@ function executeAiAssistantCodexRun(payload, context) {
2614
2717
  id_request: requestId || undefined,
2615
2718
  id_conversation: conversation._id
2616
2719
  })];
2617
- case 59:
2720
+ case 62:
2618
2721
  _14.sent();
2619
- return [3 /*break*/, 61];
2620
- case 60:
2722
+ return [3 /*break*/, 64];
2723
+ case 63:
2621
2724
  usageError_1 = _14.sent();
2622
- console.error(new Date(), 'Failed to record codex usage', usageError_1);
2623
- return [3 /*break*/, 61];
2624
- case 61:
2725
+ console.error(new Date(), 'Failed to record AI usage', usageError_1);
2726
+ return [3 /*break*/, 64];
2727
+ case 64:
2625
2728
  finalAssistantDoc = __assign(__assign(__assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: assistantContent, metadata: finalMetadata }), (finalUsage ? { usage: finalUsage } : {})), { updatedAt: finalNow });
2626
- if (!assistantMessageId) return [3 /*break*/, 63];
2729
+ if (!assistantMessageId) return [3 /*break*/, 66];
2627
2730
  setPayload = {
2628
2731
  content: assistantContent,
2629
2732
  metadata: finalMetadata,
@@ -2633,59 +2736,59 @@ function executeAiAssistantCodexRun(payload, context) {
2633
2736
  setPayload.usage = finalUsage;
2634
2737
  }
2635
2738
  return [4 /*yield*/, updateAssistantMessageWithFallback(assistantMessageId, setPayload)];
2636
- case 62:
2637
- _14.sent();
2638
- _14.label = 63;
2639
- case 63: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
2640
- case 64:
2641
- _14.sent();
2642
- if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 66];
2643
- return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
2644
2739
  case 65:
2645
2740
  _14.sent();
2646
2741
  _14.label = 66;
2647
- case 66: return [2 /*return*/, finalAssistantDoc];
2742
+ case 66: return [4 /*yield*/, touchConversation(conversation._id, finalNow, assistantMessageId ? String(assistantMessageId) : undefined)];
2648
2743
  case 67:
2744
+ _14.sent();
2745
+ if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 69];
2746
+ return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
2747
+ case 68:
2748
+ _14.sent();
2749
+ _14.label = 69;
2750
+ case 69: return [2 /*return*/, finalAssistantDoc];
2751
+ case 70:
2649
2752
  finalizeError_1 = _14.sent();
2650
2753
  failedAt = new Date();
2651
2754
  fallbackContent = assistantContent || buildAssistantCodexErrorMessage(finalizeError_1);
2652
2755
  failureMetadata = __assign(__assign(__assign({ model: codexModel }, (codexFallbackModels.length ? { model_fallbacks: codexFallbackModels } : {})), (requestId ? { request_id: requestId } : {})), { pending: false, failed: true, error_message: normalizeOptionalString(finalizeError_1 === null || finalizeError_1 === void 0 ? void 0 : finalizeError_1.message) || 'Unknown error' });
2653
- _14.label = 68;
2654
- case 68:
2655
- _14.trys.push([68, 72, , 73]);
2656
- if (!assistantMessageId) return [3 /*break*/, 70];
2756
+ _14.label = 71;
2757
+ case 71:
2758
+ _14.trys.push([71, 75, , 76]);
2759
+ if (!assistantMessageId) return [3 /*break*/, 73];
2657
2760
  return [4 /*yield*/, updateAssistantMessageWithFallback(assistantMessageId, {
2658
2761
  content: fallbackContent,
2659
2762
  metadata: failureMetadata,
2660
2763
  updatedAt: failedAt
2661
2764
  })];
2662
- case 69:
2765
+ case 72:
2663
2766
  _14.sent();
2664
- _14.label = 70;
2665
- case 70: return [4 /*yield*/, touchConversation(conversation._id, failedAt, assistantMessageId ? String(assistantMessageId) : undefined)];
2666
- case 71:
2767
+ _14.label = 73;
2768
+ case 73: return [4 /*yield*/, touchConversation(conversation._id, failedAt, assistantMessageId ? String(assistantMessageId) : undefined)];
2769
+ case 74:
2667
2770
  _14.sent();
2668
- return [3 /*break*/, 73];
2669
- case 72:
2771
+ return [3 /*break*/, 76];
2772
+ case 75:
2670
2773
  persistError_1 = _14.sent();
2671
2774
  console.error(new Date(), 'AI assistant finalize fallback update failed', persistError_1);
2672
- return [3 /*break*/, 73];
2673
- case 73:
2674
- if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 77];
2675
- _14.label = 74;
2676
- case 74:
2677
- _14.trys.push([74, 76, , 77]);
2775
+ return [3 /*break*/, 76];
2776
+ case 76:
2777
+ if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 80];
2778
+ _14.label = 77;
2779
+ case 77:
2780
+ _14.trys.push([77, 79, , 80]);
2678
2781
  return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
2679
- case 75:
2782
+ case 78:
2680
2783
  _14.sent();
2681
- return [3 /*break*/, 77];
2682
- case 76:
2784
+ return [3 /*break*/, 80];
2785
+ case 79:
2683
2786
  _k = _14.sent();
2684
- return [3 /*break*/, 77];
2685
- case 77:
2787
+ return [3 /*break*/, 80];
2788
+ case 80:
2686
2789
  console.error(new Date(), 'AI assistant run finalize failed:', finalizeError_1);
2687
2790
  return [2 /*return*/, __assign(__assign({}, assistantDoc), { _id: assistantMessageId, content: fallbackContent, metadata: failureMetadata, updatedAt: failedAt })];
2688
- case 78: return [2 /*return*/];
2791
+ case 81: return [2 /*return*/];
2689
2792
  }
2690
2793
  });
2691
2794
  }); });
@@ -2928,7 +3031,7 @@ function executeAiAssistantReportIssue(payload, context) {
2928
3031
  }
2929
3032
  function executeAiAssistantMongoRead(payload, context) {
2930
3033
  return __awaiter(this, void 0, void 0, function () {
2931
- var input, rawCollection, retryState, triedCollections, crossCollectionRetryEnabled, dbName, db, collectionResolution, collection, bridgeCollection, retryRootCollection, schemaFields, effectivePermissionView, _a, user, isSuperAdmin, canViewDebug, customerId, fallbackMeta, baseQuery, stripped, userId, normalizedClient, shouldScopeByClient, _b, strippedClient, clientScopedQuery, scopedQuery, normalized, findOptions, runFindWithRepair, initialRead, documents, executedQuery, probeDocs, dateFallback, fallbackQuery, fallbackRead, fallbackDocs, expanded, fallbackRead, fallbackDocs, nameFallback, fallbackRead, fallbackDocs, _c, chemicalLookup, fallbackRead, fallbackDocs, queryFields, _d, aliases, rewrittenQuery, fallbackRead, fallbackDocs, _e, activeFallback, fallbackRead, fallbackDocs, _f, idLookup, fallbackRead, fallbackDocs, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, hasActiveStatusFilters, crossCollectionCandidates, crossCollectionCandidates_1, crossCollectionCandidates_1_1, candidateCollection, fallbackPayload, fallbackResult, fallbackDocs, existingFallbacks, rejectedQuality, error_5, existingErrors, e_1_1, nameFields, dateFields, diagnostics, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, total, sanitizedDocuments, requestedFields, missingFields, _o, projectionAliases, expandedProjection, refreshedDocs, includeIds, fieldAliases, displayDocs, idLookupDisplay, priorityFields, displayMaxRows, display;
3034
+ var input, rawCollection, retryState, triedCollections, crossCollectionRetryEnabled, dbName, db, collectionResolution, collection, bridgeCollection, retryRootCollection, schemaFields, effectivePermissionView, _a, user, isSuperAdmin, canViewDebug, customerId, fallbackMeta, runtimeControl, runtimeFastMode, activeRuntimeControl, hasReadRuntimeBudget, resolveReadMaxTimeMS, baseQuery, stripped, userId, normalizedClient, shouldScopeByClient, _b, strippedClient, clientScopedQuery, scopedQuery, normalized, findOptions, buildFindOptions, buildCountOptions, runFindWithRepair, initialRead, documents, executedQuery, probeDocs, dateFallback, fallbackQuery, fallbackRead, fallbackDocs, expanded, fallbackRead, fallbackDocs, nameFallback, fallbackRead, fallbackDocs, _c, chemicalLookup, fallbackRead, fallbackDocs, queryFields, _d, aliases, rewrittenQuery, fallbackRead, fallbackDocs, _e, activeFallback, fallbackRead, fallbackDocs, _f, idLookup, fallbackRead, fallbackDocs, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, hasActiveStatusFilters, crossCollectionCandidates, crossCollectionCandidates_1, crossCollectionCandidates_1_1, candidateCollection, fallbackPayload, fallbackResult, fallbackDocs, existingFallbacks, rejectedQuality, error_5, existingErrors, e_1_1, nameFields, dateFields, diagnostics, countOptions, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, total, sanitizedDocuments, requestedFields, missingFields, _o, projectionAliases, expandedProjection, refreshedDocs, includeIds, fieldAliases, displayDocs, idLookupDisplay, priorityFields, displayMaxRows, display;
2932
3035
  var e_1, _p;
2933
3036
  var _this = this;
2934
3037
  var _q, _r;
@@ -2972,6 +3075,26 @@ function executeAiAssistantMongoRead(payload, context) {
2972
3075
  }
2973
3076
  customerId = normalizeOptionalString((_q = user === null || user === void 0 ? void 0 : user.other) === null || _q === void 0 ? void 0 : _q.id_customer);
2974
3077
  fallbackMeta = {};
3078
+ runtimeControl = normalizeAssistantRuntimeControl(input.__assistantRuntime);
3079
+ runtimeFastMode = (runtimeControl === null || runtimeControl === void 0 ? void 0 : runtimeControl.fastMode) === undefined
3080
+ ? resolveAssistantFastModeEnabled()
3081
+ : runtimeControl.fastMode === true;
3082
+ activeRuntimeControl = runtimeFastMode ? runtimeControl : null;
3083
+ hasReadRuntimeBudget = function (stage, minimumMs) {
3084
+ if (minimumMs === void 0) { minimumMs = AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS; }
3085
+ if (!hasAssistantRuntimeBudget(activeRuntimeControl, minimumMs)) {
3086
+ fallbackMeta.runtimeBudget = {
3087
+ stage: stage,
3088
+ exhausted: true,
3089
+ deadlineMs: (activeRuntimeControl === null || activeRuntimeControl === void 0 ? void 0 : activeRuntimeControl.deadlineMs) || undefined
3090
+ };
3091
+ return false;
3092
+ }
3093
+ return true;
3094
+ };
3095
+ resolveReadMaxTimeMS = function () { return resolveAssistantEffectiveMongoMaxTimeMs({
3096
+ runtime: activeRuntimeControl
3097
+ }); };
2975
3098
  if (bridgeCollection.fallbackFrom) {
2976
3099
  fallbackMeta.reportBuilderBridge = {
2977
3100
  from: bridgeCollection.fallbackFrom,
@@ -3029,17 +3152,33 @@ function executeAiAssistantMongoRead(payload, context) {
3029
3152
  scopedQuery = applyCustomerScopeFilter(clientScopedQuery, collection, customerId, isSuperAdmin);
3030
3153
  normalized = normalizeAssistantFindOptions(input.options);
3031
3154
  findOptions = __assign(__assign({}, normalized.findOptions), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
3155
+ buildFindOptions = function () {
3156
+ var maxTimeMS = resolveReadMaxTimeMS();
3157
+ return maxTimeMS ? __assign(__assign({}, findOptions), { maxTimeMS: maxTimeMS }) : findOptions;
3158
+ };
3159
+ buildCountOptions = function () {
3160
+ var maxTimeMS = resolveReadMaxTimeMS();
3161
+ return maxTimeMS
3162
+ ? { readPreference: AI_ASSISTANT_READ_PREFERENCE, maxTimeMS: maxTimeMS }
3163
+ : { readPreference: AI_ASSISTANT_READ_PREFERENCE };
3164
+ };
3032
3165
  runFindWithRepair = function (query, stage) { return __awaiter(_this, void 0, void 0, function () {
3033
- var docs, error_6, repaired, docs;
3166
+ var stageFindOptions, docs, error_6, repaired, docs;
3034
3167
  return __generator(this, function (_a) {
3035
3168
  switch (_a.label) {
3036
3169
  case 0:
3037
- _a.trys.push([0, 2, , 4]);
3038
- return [4 /*yield*/, db.collection(collection).find(query, findOptions).toArray()];
3170
+ if (!hasReadRuntimeBudget(stage)) {
3171
+ return [2 /*return*/, { documents: [], query: query }];
3172
+ }
3173
+ stageFindOptions = buildFindOptions();
3174
+ _a.label = 1;
3039
3175
  case 1:
3176
+ _a.trys.push([1, 3, , 5]);
3177
+ return [4 /*yield*/, db.collection(collection).find(query, stageFindOptions).toArray()];
3178
+ case 2:
3040
3179
  docs = _a.sent();
3041
3180
  return [2 /*return*/, { documents: docs, query: query }];
3042
- case 2:
3181
+ case 3:
3043
3182
  error_6 = _a.sent();
3044
3183
  if (!isAssistantDateArithmeticArgumentError(error_6)) {
3045
3184
  throw error_6;
@@ -3048,8 +3187,8 @@ function executeAiAssistantMongoRead(payload, context) {
3048
3187
  if (!repaired.changed || containsForbiddenMongoOperators(repaired.query)) {
3049
3188
  throw error_6;
3050
3189
  }
3051
- return [4 /*yield*/, db.collection(collection).find(repaired.query, findOptions).toArray()];
3052
- case 3:
3190
+ return [4 /*yield*/, db.collection(collection).find(repaired.query, stageFindOptions).toArray()];
3191
+ case 4:
3053
3192
  docs = _a.sent();
3054
3193
  fallbackMeta.dateArithmetic = {
3055
3194
  attempted: true,
@@ -3061,7 +3200,7 @@ function executeAiAssistantMongoRead(payload, context) {
3061
3200
  documents: docs,
3062
3201
  query: repaired.query
3063
3202
  }];
3064
- case 4: return [2 /*return*/];
3203
+ case 5: return [2 /*return*/];
3065
3204
  }
3066
3205
  });
3067
3206
  }); };
@@ -3135,7 +3274,8 @@ function executeAiAssistantMongoRead(payload, context) {
3135
3274
  idClient: normalizedClient,
3136
3275
  idCustomer: customerId,
3137
3276
  isSuperAdmin: isSuperAdmin,
3138
- includeClientScope: shouldScopeByClient
3277
+ includeClientScope: shouldScopeByClient,
3278
+ maxTimeMS: resolveReadMaxTimeMS()
3139
3279
  })];
3140
3280
  case 14:
3141
3281
  _c = (_s.sent());
@@ -3177,7 +3317,8 @@ function executeAiAssistantMongoRead(payload, context) {
3177
3317
  idClient: normalizedClient,
3178
3318
  idCustomer: customerId,
3179
3319
  isSuperAdmin: isSuperAdmin,
3180
- includeClientScope: shouldScopeByClient
3320
+ includeClientScope: shouldScopeByClient,
3321
+ maxTimeMS: resolveReadMaxTimeMS()
3181
3322
  })];
3182
3323
  case 19:
3183
3324
  _d = (_s.sent());
@@ -3217,7 +3358,8 @@ function executeAiAssistantMongoRead(payload, context) {
3217
3358
  idClient: normalizedClient,
3218
3359
  idCustomer: customerId,
3219
3360
  isSuperAdmin: isSuperAdmin,
3220
- includeClientScope: shouldScopeByClient
3361
+ includeClientScope: shouldScopeByClient,
3362
+ maxTimeMS: resolveReadMaxTimeMS()
3221
3363
  })];
3222
3364
  case 23:
3223
3365
  _e = (_s.sent());
@@ -3252,7 +3394,8 @@ function executeAiAssistantMongoRead(payload, context) {
3252
3394
  idClient: normalizedClient,
3253
3395
  idCustomer: customerId,
3254
3396
  isSuperAdmin: isSuperAdmin,
3255
- includeClientScope: shouldScopeByClient
3397
+ includeClientScope: shouldScopeByClient,
3398
+ maxTimeMS: resolveReadMaxTimeMS()
3256
3399
  })];
3257
3400
  case 27:
3258
3401
  _f = (_s.sent());
@@ -3283,7 +3426,7 @@ function executeAiAssistantMongoRead(payload, context) {
3283
3426
  }
3284
3427
  _s.label = 31;
3285
3428
  case 31:
3286
- if (!!documents.length) return [3 /*break*/, 34];
3429
+ if (!(!documents.length && hasReadRuntimeBudget('report_fallback'))) return [3 /*break*/, 34];
3287
3430
  return [4 /*yield*/, resolveBaseCollectionFromReport(db, dbName, collection)];
3288
3431
  case 32:
3289
3432
  baseCollection = _s.sent();
@@ -3314,7 +3457,7 @@ function executeAiAssistantMongoRead(payload, context) {
3314
3457
  _s.label = 34;
3315
3458
  case 34:
3316
3459
  hasActiveStatusFilters = collectAssistantActiveMatchFields(executedQuery).length > 0;
3317
- if (!(!documents.length && crossCollectionRetryEnabled && !hasActiveStatusFilters)) return [3 /*break*/, 46];
3460
+ if (!(!documents.length && crossCollectionRetryEnabled && !hasActiveStatusFilters && hasReadRuntimeBudget('collection_retry'))) return [3 /*break*/, 46];
3318
3461
  return [4 /*yield*/, resolveAssistantAvailableCrossCollectionFallbacks(db, dbName, collection, triedCollections, {
3319
3462
  fieldHints: extractQueryFieldPaths(executedQuery || {})
3320
3463
  })];
@@ -3414,7 +3557,7 @@ function executeAiAssistantMongoRead(payload, context) {
3414
3557
  }
3415
3558
  _s.label = 47;
3416
3559
  case 47:
3417
- if (!(!documents.length && canViewDebug)) return [3 /*break*/, 64];
3560
+ if (!(!documents.length && canViewDebug && hasReadRuntimeBudget('zero_diagnostics', 20))) return [3 /*break*/, 64];
3418
3561
  nameFields = collectMatchFieldsByCondition(executedQuery, function (field, condition) { return isRegexMatchCondition(condition)
3419
3562
  || (typeof condition === 'string' && shouldApplyAssistantNameRegex(field)); });
3420
3563
  dateFields = collectMatchFieldsByCondition(executedQuery, function (_field, condition) { return isDateCondition(condition); });
@@ -3425,12 +3568,11 @@ function executeAiAssistantMongoRead(payload, context) {
3425
3568
  _s.label = 48;
3426
3569
  case 48:
3427
3570
  _s.trys.push([48, 53, , 54]);
3571
+ countOptions = buildCountOptions();
3428
3572
  if (!nameFields.length) return [3 /*break*/, 50];
3429
3573
  queryNoName = stripMatchFields(executedQuery, nameFields);
3430
3574
  _g = diagnostics;
3431
- return [4 /*yield*/, db.collection(collection).countDocuments(queryNoName, {
3432
- readPreference: AI_ASSISTANT_READ_PREFERENCE
3433
- })];
3575
+ return [4 /*yield*/, db.collection(collection).countDocuments(queryNoName, countOptions)];
3434
3576
  case 49:
3435
3577
  _g.recentCount = _s.sent();
3436
3578
  _s.label = 50;
@@ -3438,9 +3580,7 @@ function executeAiAssistantMongoRead(payload, context) {
3438
3580
  if (!dateFields.length) return [3 /*break*/, 52];
3439
3581
  queryNoDate = stripMatchFields(executedQuery, dateFields);
3440
3582
  _h = diagnostics;
3441
- return [4 /*yield*/, db.collection(collection).countDocuments(queryNoDate, {
3442
- readPreference: AI_ASSISTANT_READ_PREFERENCE
3443
- })];
3583
+ return [4 /*yield*/, db.collection(collection).countDocuments(queryNoDate, countOptions)];
3444
3584
  case 51:
3445
3585
  _h.nameMatchCount = _s.sent();
3446
3586
  _s.label = 52;
@@ -3458,7 +3598,8 @@ function executeAiAssistantMongoRead(payload, context) {
3458
3598
  idClient: normalizedClient,
3459
3599
  idCustomer: customerId,
3460
3600
  isSuperAdmin: isSuperAdmin,
3461
- includeClientScope: shouldScopeByClient
3601
+ includeClientScope: shouldScopeByClient,
3602
+ maxTimeMS: resolveReadMaxTimeMS()
3462
3603
  })];
3463
3604
  case 55:
3464
3605
  _k = (_s.sent());
@@ -3480,7 +3621,7 @@ function executeAiAssistantMongoRead(payload, context) {
3480
3621
  base = stripVersionSuffix(collection.startsWith('report-') ? collection.slice('report-'.length) : collection);
3481
3622
  alt = collection.startsWith('report-') ? base : "report-".concat(base);
3482
3623
  if (!(alt && alt !== collection && allCollections.includes(alt))) return [3 /*break*/, 61];
3483
- return [4 /*yield*/, db.collection(alt).countDocuments({}, { readPreference: AI_ASSISTANT_READ_PREFERENCE })];
3624
+ return [4 /*yield*/, db.collection(alt).countDocuments({}, buildCountOptions())];
3484
3625
  case 60:
3485
3626
  altCount = _s.sent();
3486
3627
  diagnostics.alternateCollection = alt;
@@ -3495,8 +3636,8 @@ function executeAiAssistantMongoRead(payload, context) {
3495
3636
  _s.label = 64;
3496
3637
  case 64:
3497
3638
  total = null;
3498
- if (!normalized.includeTotal) return [3 /*break*/, 66];
3499
- return [4 /*yield*/, db.collection(collection).countDocuments(executedQuery, { readPreference: AI_ASSISTANT_READ_PREFERENCE })];
3639
+ if (!(normalized.includeTotal && hasReadRuntimeBudget('total_count', 20))) return [3 /*break*/, 66];
3640
+ return [4 /*yield*/, db.collection(collection).countDocuments(executedQuery, buildCountOptions())];
3500
3641
  case 65:
3501
3642
  total = _s.sent();
3502
3643
  _s.label = 66;
@@ -3516,7 +3657,8 @@ function executeAiAssistantMongoRead(payload, context) {
3516
3657
  idClient: normalizedClient,
3517
3658
  idCustomer: customerId,
3518
3659
  isSuperAdmin: isSuperAdmin,
3519
- includeClientScope: shouldScopeByClient
3660
+ includeClientScope: shouldScopeByClient,
3661
+ maxTimeMS: resolveReadMaxTimeMS()
3520
3662
  })];
3521
3663
  case 67:
3522
3664
  _o = (_s.sent());
@@ -3535,7 +3677,7 @@ function executeAiAssistantMongoRead(payload, context) {
3535
3677
  if (!(expandedProjection && expandedProjection !== findOptions.projection)) return [3 /*break*/, 70];
3536
3678
  findOptions = __assign(__assign({}, findOptions), { projection: expandedProjection });
3537
3679
  normalized.findOptions.projection = expandedProjection;
3538
- return [4 /*yield*/, db.collection(collection).find(executedQuery, findOptions).toArray()];
3680
+ return [4 /*yield*/, db.collection(collection).find(executedQuery, buildFindOptions()).toArray()];
3539
3681
  case 69:
3540
3682
  refreshedDocs = _s.sent();
3541
3683
  if (refreshedDocs.length) {
@@ -3607,12 +3749,12 @@ function executeAiAssistantMongoRead(payload, context) {
3607
3749
  }
3608
3750
  function executeAiAssistantMongoAggregate(payload, context) {
3609
3751
  return __awaiter(this, void 0, void 0, function () {
3610
- var input, rawCollection, retryState, triedCollections, crossCollectionRetryEnabled, dbName, db, collectionResolution, collection, bridgeCollection, retryRootCollection, schemaFields, effectivePermissionView, _a, user, isSuperAdmin, canViewDebug, 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, nestedFallbacks, nestedFallbacks_1, nestedFallbacks_1_1, nestedFallback, fallbackPayload, fallbackResult, existingFallbacks, error_7, errorMessage, existingErrors, e_2_1, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, fallbackAcceptanceOptions, crossCollectionCandidates, crossCollectionCandidates_2, crossCollectionCandidates_2_1, candidateCollection, fallbackPayload, fallbackResult, fallbackDocs, fallbackQuality, existingFallbacks, rejectedQuality, error_8, existingErrors, e_3_1, matchStages, diagnostics, combinedMatch, nameFields, dateFields, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, verification, sanitizedDocuments, includeIds, displayDocs, idLookupDisplay, display;
3611
- var e_2, _o, e_3, _p;
3752
+ var input, rawCollection, retryState, triedCollections, crossCollectionRetryEnabled, dbName, db, collectionResolution, collection, bridgeCollection, retryRootCollection, schemaFields, effectivePermissionView, _a, user, isSuperAdmin, canViewDebug, customerId, fallbackMeta, runtimeControl, runtimeFastMode, activeRuntimeControl, hasAggregateRuntimeBudget, resolveAggregateMaxTimeMS, baseQuery, stripped, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, sanitizedPipeline, strippedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, executedPipeline, dateField, buildAggregateOptions, buildAggregateCountOptions, 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, nestedFallbacks, nestedFallbacks_1, nestedFallbacks_1_1, nestedFallback, fallbackPayload, fallbackResult, existingFallbacks, error_7, errorMessage, existingErrors, e_2_1, baseCollection, fallbackPayload, fallbackResult, existingFallbacks, fallbackAcceptanceOptions, crossCollectionCandidates, crossCollectionCandidates_2, crossCollectionCandidates_2_1, candidateCollection, fallbackPayload, fallbackResult, fallbackDocs, fallbackQuality, existingFallbacks, rejectedQuality, error_8, existingErrors, e_3_1, matchStages, diagnostics, combinedMatch, nameFields, dateFields, countOptions, queryNoName, _g, queryNoDate, _h, _j, _k, _l, allCollections, base, alt, altCount, _m, verification, _o, sanitizedDocuments, includeIds, displayDocs, idLookupDisplay, display;
3753
+ var e_2, _p, e_3, _q;
3612
3754
  var _this = this;
3613
- var _q, _r;
3614
- return __generator(this, function (_s) {
3615
- switch (_s.label) {
3755
+ var _r, _s;
3756
+ return __generator(this, function (_t) {
3757
+ switch (_t.label) {
3616
3758
  case 0:
3617
3759
  input = payload || {};
3618
3760
  rawCollection = normalizeOptionalString(input.collection);
@@ -3629,11 +3771,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
3629
3771
  db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
3630
3772
  return [4 /*yield*/, resolveAssistantCollectionName(db, dbName, rawCollection)];
3631
3773
  case 1:
3632
- collectionResolution = _s.sent();
3774
+ collectionResolution = _t.sent();
3633
3775
  collection = collectionResolution.name || rawCollection;
3634
3776
  return [4 /*yield*/, resolveAssistantReportBuilderBridgeCollection(collection, db, dbName)];
3635
3777
  case 2:
3636
- bridgeCollection = _s.sent();
3778
+ bridgeCollection = _t.sent();
3637
3779
  if (bridgeCollection.fallbackFrom) {
3638
3780
  collection = bridgeCollection.collection;
3639
3781
  }
@@ -3645,12 +3787,33 @@ function executeAiAssistantMongoAggregate(payload, context) {
3645
3787
  : input.permissionView;
3646
3788
  return [4 /*yield*/, ensureAssistantReadAccess(context, effectivePermissionView, collection)];
3647
3789
  case 3:
3648
- _a = _s.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin, canViewDebug = _a.canViewDebug;
3790
+ _a = _t.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin, canViewDebug = _a.canViewDebug;
3649
3791
  if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
3650
3792
  throw new Error('AI assistant report builder bridge: Access denied.');
3651
3793
  }
3652
- customerId = normalizeOptionalString((_q = user === null || user === void 0 ? void 0 : user.other) === null || _q === void 0 ? void 0 : _q.id_customer);
3794
+ customerId = normalizeOptionalString((_r = user === null || user === void 0 ? void 0 : user.other) === null || _r === void 0 ? void 0 : _r.id_customer);
3653
3795
  fallbackMeta = {};
3796
+ runtimeControl = normalizeAssistantRuntimeControl(input.__assistantRuntime);
3797
+ runtimeFastMode = (runtimeControl === null || runtimeControl === void 0 ? void 0 : runtimeControl.fastMode) === undefined
3798
+ ? resolveAssistantFastModeEnabled()
3799
+ : runtimeControl.fastMode === true;
3800
+ activeRuntimeControl = runtimeFastMode ? runtimeControl : null;
3801
+ hasAggregateRuntimeBudget = function (stage, minimumMs) {
3802
+ if (minimumMs === void 0) { minimumMs = AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS; }
3803
+ if (!hasAssistantRuntimeBudget(activeRuntimeControl, minimumMs)) {
3804
+ fallbackMeta.runtimeBudget = {
3805
+ stage: stage,
3806
+ exhausted: true,
3807
+ deadlineMs: (activeRuntimeControl === null || activeRuntimeControl === void 0 ? void 0 : activeRuntimeControl.deadlineMs) || undefined
3808
+ };
3809
+ return false;
3810
+ }
3811
+ return true;
3812
+ };
3813
+ resolveAggregateMaxTimeMS = function (requestedMaxTimeMS) { return resolveAssistantEffectiveMongoMaxTimeMs({
3814
+ requestedMaxTimeMS: requestedMaxTimeMS,
3815
+ runtime: activeRuntimeControl
3816
+ }); };
3654
3817
  if (bridgeCollection.fallbackFrom) {
3655
3818
  fallbackMeta.reportBuilderBridge = {
3656
3819
  from: bridgeCollection.fallbackFrom,
@@ -3686,11 +3849,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
3686
3849
  if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 5];
3687
3850
  return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
3688
3851
  case 4:
3689
- _b = _s.sent();
3852
+ _b = _t.sent();
3690
3853
  return [3 /*break*/, 6];
3691
3854
  case 5:
3692
3855
  _b = false;
3693
- _s.label = 6;
3856
+ _t.label = 6;
3694
3857
  case 6:
3695
3858
  shouldScopeByClient = _b;
3696
3859
  clientScopedQuery = shouldScopeByClient
@@ -3716,20 +3879,35 @@ function executeAiAssistantMongoAggregate(payload, context) {
3716
3879
  if (containsForbiddenMongoOperators(executedPipeline)) {
3717
3880
  throw new Error('AI assistant report builder bridge: Pipeline contains restricted operators.');
3718
3881
  }
3719
- aggregateOptions = __assign(__assign({}, normalizedOptions.aggregateOptions), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
3882
+ buildAggregateOptions = function () {
3883
+ var maxTimeMS = resolveAggregateMaxTimeMS(normalizedOptions.aggregateOptions.maxTimeMS);
3884
+ return __assign(__assign(__assign({}, normalizedOptions.aggregateOptions), (maxTimeMS ? { maxTimeMS: maxTimeMS } : {})), { readPreference: AI_ASSISTANT_READ_PREFERENCE });
3885
+ };
3886
+ buildAggregateCountOptions = function () {
3887
+ var maxTimeMS = resolveAggregateMaxTimeMS(normalizedOptions.aggregateOptions.maxTimeMS);
3888
+ return maxTimeMS
3889
+ ? { readPreference: AI_ASSISTANT_READ_PREFERENCE, maxTimeMS: maxTimeMS }
3890
+ : { readPreference: AI_ASSISTANT_READ_PREFERENCE };
3891
+ };
3720
3892
  runAggregateWithRepair = function (pipeline, stage) { return __awaiter(_this, void 0, void 0, function () {
3721
- var docs, error_9, isDateRepair, isRankSortByRepair, isDottedOutputFieldRepair, repaired, dottedFieldPath, dottedFieldReferenceRepairUsed, pathReferenceRepair, docs;
3893
+ var aggregateOptions, docs, error_9, isDateRepair, isRankSortByRepair, isDottedOutputFieldRepair, repaired, dottedFieldPath, dottedFieldReferenceRepairUsed, pathReferenceRepair, docs;
3722
3894
  return __generator(this, function (_a) {
3723
3895
  switch (_a.label) {
3724
3896
  case 0:
3725
- _a.trys.push([0, 2, , 4]);
3897
+ if (!hasAggregateRuntimeBudget(stage)) {
3898
+ return [2 /*return*/, { documents: [], pipeline: pipeline }];
3899
+ }
3900
+ aggregateOptions = buildAggregateOptions();
3901
+ _a.label = 1;
3902
+ case 1:
3903
+ _a.trys.push([1, 3, , 5]);
3726
3904
  return [4 /*yield*/, db.collection(collection)
3727
3905
  .aggregate(pipeline, aggregateOptions)
3728
3906
  .toArray()];
3729
- case 1:
3907
+ case 2:
3730
3908
  docs = _a.sent();
3731
3909
  return [2 /*return*/, { documents: docs, pipeline: pipeline }];
3732
- case 2:
3910
+ case 3:
3733
3911
  error_9 = _a.sent();
3734
3912
  isDateRepair = isAssistantDateArithmeticArgumentError(error_9);
3735
3913
  isRankSortByRepair = isAssistantRankSortByError(error_9);
@@ -3763,7 +3941,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
3763
3941
  return [4 /*yield*/, db.collection(collection)
3764
3942
  .aggregate(repaired.pipeline, aggregateOptions)
3765
3943
  .toArray()];
3766
- case 3:
3944
+ case 4:
3767
3945
  docs = _a.sent();
3768
3946
  if (isDateRepair) {
3769
3947
  fallbackMeta.dateArithmetic = {
@@ -3793,13 +3971,13 @@ function executeAiAssistantMongoAggregate(payload, context) {
3793
3971
  };
3794
3972
  }
3795
3973
  return [2 /*return*/, { documents: docs, pipeline: repaired.pipeline }];
3796
- case 4: return [2 /*return*/];
3974
+ case 5: return [2 /*return*/];
3797
3975
  }
3798
3976
  });
3799
3977
  }); };
3800
3978
  return [4 /*yield*/, runAggregateWithRepair(executedPipeline, 'initial')];
3801
3979
  case 7:
3802
- initialAggregate = _s.sent();
3980
+ initialAggregate = _t.sent();
3803
3981
  documents = initialAggregate.documents;
3804
3982
  executedPipeline = initialAggregate.pipeline;
3805
3983
  dateField = findAggregateDateField(executedPipeline);
@@ -3812,14 +3990,14 @@ function executeAiAssistantMongoAggregate(payload, context) {
3812
3990
  if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 9];
3813
3991
  return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'date_field_fallback')];
3814
3992
  case 8:
3815
- fallbackAggregate = _s.sent();
3993
+ fallbackAggregate = _t.sent();
3816
3994
  fallbackDocs = fallbackAggregate.documents;
3817
3995
  if (fallbackDocs.length) {
3818
3996
  documents = fallbackDocs;
3819
3997
  executedPipeline = fallbackAggregate.pipeline;
3820
3998
  fallbackMeta.dateField.used = true;
3821
3999
  }
3822
- _s.label = 9;
4000
+ _t.label = 9;
3823
4001
  case 9:
3824
4002
  if (!(!documents.length && dateField !== 'createdAt')) return [3 /*break*/, 11];
3825
4003
  createdFallback = { from: dateField, to: 'createdAt', attempted: true, used: false };
@@ -3828,14 +4006,14 @@ function executeAiAssistantMongoAggregate(payload, context) {
3828
4006
  if (!!containsForbiddenMongoOperators(createdPipeline)) return [3 /*break*/, 11];
3829
4007
  return [4 /*yield*/, runAggregateWithRepair(createdPipeline, 'date_field_created_at')];
3830
4008
  case 10:
3831
- createdAggregate = _s.sent();
4009
+ createdAggregate = _t.sent();
3832
4010
  createdDocs = createdAggregate.documents;
3833
4011
  if (createdDocs.length) {
3834
4012
  documents = createdDocs;
3835
4013
  executedPipeline = createdAggregate.pipeline;
3836
4014
  fallbackMeta.dateFieldCreatedAt.used = true;
3837
4015
  }
3838
- _s.label = 11;
4016
+ _t.label = 11;
3839
4017
  case 11:
3840
4018
  if (!!documents.length) return [3 /*break*/, 13];
3841
4019
  expanded = expandAggregateDateMatchFallback(executedPipeline, schemaFields);
@@ -3848,14 +4026,14 @@ function executeAiAssistantMongoAggregate(payload, context) {
3848
4026
  if (!!containsForbiddenMongoOperators(expanded.pipeline)) return [3 /*break*/, 13];
3849
4027
  return [4 /*yield*/, runAggregateWithRepair(expanded.pipeline, 'date_fields_expanded')];
3850
4028
  case 12:
3851
- expandedAggregate = _s.sent();
4029
+ expandedAggregate = _t.sent();
3852
4030
  expandedDocs = expandedAggregate.documents;
3853
4031
  if (expandedDocs.length) {
3854
4032
  documents = expandedDocs;
3855
4033
  executedPipeline = expandedAggregate.pipeline;
3856
4034
  fallbackMeta.dateFieldsExpanded.used = true;
3857
4035
  }
3858
- _s.label = 13;
4036
+ _t.label = 13;
3859
4037
  case 13:
3860
4038
  if (!!documents.length) return [3 /*break*/, 17];
3861
4039
  completionFallback = resolveAggregateCompletionFallback(executedPipeline);
@@ -3872,14 +4050,14 @@ function executeAiAssistantMongoAggregate(payload, context) {
3872
4050
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 15];
3873
4051
  return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'completion_add_fields')];
3874
4052
  case 14:
3875
- fallbackAggregate = _s.sent();
4053
+ fallbackAggregate = _t.sent();
3876
4054
  fallbackDocs = fallbackAggregate.documents;
3877
4055
  if (fallbackDocs.length) {
3878
4056
  documents = fallbackDocs;
3879
4057
  executedPipeline = fallbackAggregate.pipeline;
3880
4058
  fallbackMeta.completion.used = true;
3881
4059
  }
3882
- _s.label = 15;
4060
+ _t.label = 15;
3883
4061
  case 15:
3884
4062
  if (!!documents.length) return [3 /*break*/, 17];
3885
4063
  completionExprFallback = resolveAggregateCompletionExprFallback(executedPipeline);
@@ -3896,23 +4074,23 @@ function executeAiAssistantMongoAggregate(payload, context) {
3896
4074
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 17];
3897
4075
  return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'completion_expr')];
3898
4076
  case 16:
3899
- fallbackAggregate = _s.sent();
4077
+ fallbackAggregate = _t.sent();
3900
4078
  fallbackDocs = fallbackAggregate.documents;
3901
4079
  if (fallbackDocs.length) {
3902
4080
  documents = fallbackDocs;
3903
4081
  executedPipeline = fallbackAggregate.pipeline;
3904
4082
  fallbackMeta.completion.used = true;
3905
4083
  }
3906
- _s.label = 17;
4084
+ _t.label = 17;
3907
4085
  case 17:
3908
4086
  if (!(documents.length <= 1)) return [3 /*break*/, 26];
3909
4087
  unwindFallback = resolveAggregateUnwindFallback(executedPipeline);
3910
4088
  if (!unwindFallback) return [3 /*break*/, 26];
3911
4089
  fallbackMeta.unwind = { path: unwindFallback.path, attempted: true, used: false };
3912
4090
  shouldUnwind = false;
3913
- _s.label = 18;
4091
+ _t.label = 18;
3914
4092
  case 18:
3915
- _s.trys.push([18, 21, , 22]);
4093
+ _t.trys.push([18, 21, , 22]);
3916
4094
  _c = probeDocs;
3917
4095
  if (_c) return [3 /*break*/, 20];
3918
4096
  return [4 /*yield*/, fetchAssistantProbeDocs({
@@ -3921,17 +4099,18 @@ function executeAiAssistantMongoAggregate(payload, context) {
3921
4099
  idClient: normalizedClient,
3922
4100
  idCustomer: customerId,
3923
4101
  isSuperAdmin: isSuperAdmin,
3924
- includeClientScope: shouldScopeByClient
4102
+ includeClientScope: shouldScopeByClient,
4103
+ maxTimeMS: resolveAggregateMaxTimeMS()
3925
4104
  })];
3926
4105
  case 19:
3927
- _c = (_s.sent());
3928
- _s.label = 20;
4106
+ _c = (_t.sent());
4107
+ _t.label = 20;
3929
4108
  case 20:
3930
4109
  probeDocs = _c;
3931
4110
  shouldUnwind = probeDocs.length ? hasArrayValueAtPath(probeDocs, unwindFallback.path) : false;
3932
4111
  return [3 /*break*/, 22];
3933
4112
  case 21:
3934
- _d = _s.sent();
4113
+ _d = _t.sent();
3935
4114
  shouldUnwind = false;
3936
4115
  return [3 /*break*/, 22];
3937
4116
  case 22:
@@ -3940,18 +4119,18 @@ function executeAiAssistantMongoAggregate(payload, context) {
3940
4119
  if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 24];
3941
4120
  return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'unwind')];
3942
4121
  case 23:
3943
- fallbackAggregate = _s.sent();
4122
+ fallbackAggregate = _t.sent();
3944
4123
  fallbackDocs = fallbackAggregate.documents;
3945
4124
  if (fallbackDocs.length > documents.length) {
3946
4125
  documents = fallbackDocs;
3947
4126
  executedPipeline = fallbackAggregate.pipeline;
3948
4127
  fallbackMeta.unwind.used = true;
3949
4128
  }
3950
- _s.label = 24;
4129
+ _t.label = 24;
3951
4130
  case 24: return [3 /*break*/, 26];
3952
4131
  case 25:
3953
4132
  fallbackMeta.unwind.skipped = 'not_array';
3954
- _s.label = 26;
4133
+ _t.label = 26;
3955
4134
  case 26:
3956
4135
  if (!!documents.length) return [3 /*break*/, 28];
3957
4136
  nameFallback = resolveAggregateNameMatchFallback(executedPipeline);
@@ -3966,14 +4145,14 @@ function executeAiAssistantMongoAggregate(payload, context) {
3966
4145
  if (!(fallbackPipeline.length && !containsForbiddenMongoOperators(fallbackPipeline))) return [3 /*break*/, 28];
3967
4146
  return [4 /*yield*/, runAggregateWithRepair(fallbackPipeline, 'name_match')];
3968
4147
  case 27:
3969
- fallbackAggregate = _s.sent();
4148
+ fallbackAggregate = _t.sent();
3970
4149
  fallbackDocs = fallbackAggregate.documents;
3971
4150
  if (fallbackDocs.length) {
3972
4151
  documents = fallbackDocs;
3973
4152
  executedPipeline = fallbackAggregate.pipeline;
3974
4153
  fallbackMeta.nameMatch.used = true;
3975
4154
  }
3976
- _s.label = 28;
4155
+ _t.label = 28;
3977
4156
  case 28:
3978
4157
  if (!!documents.length) return [3 /*break*/, 34];
3979
4158
  _e = probeDocs;
@@ -3984,17 +4163,18 @@ function executeAiAssistantMongoAggregate(payload, context) {
3984
4163
  idClient: normalizedClient,
3985
4164
  idCustomer: customerId,
3986
4165
  isSuperAdmin: isSuperAdmin,
3987
- includeClientScope: shouldScopeByClient
4166
+ includeClientScope: shouldScopeByClient,
4167
+ maxTimeMS: resolveAggregateMaxTimeMS()
3988
4168
  })];
3989
4169
  case 29:
3990
- _e = (_s.sent());
3991
- _s.label = 30;
4170
+ _e = (_t.sent());
4171
+ _t.label = 30;
3992
4172
  case 30:
3993
4173
  probeDocs = _e;
3994
4174
  _loop_1 = function (i) {
3995
4175
  var stage, chemicalLookup, rewrittenPipeline, fallbackAggregate, fallbackDocs;
3996
- return __generator(this, function (_t) {
3997
- switch (_t.label) {
4176
+ return __generator(this, function (_u) {
4177
+ switch (_u.label) {
3998
4178
  case 0:
3999
4179
  stage = executedPipeline[i];
4000
4180
  if (!stage || typeof stage !== 'object' || !stage.$match || typeof stage.$match !== 'object') {
@@ -4010,7 +4190,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4010
4190
  probeDocs: probeDocs || undefined
4011
4191
  })];
4012
4192
  case 1:
4013
- chemicalLookup = _t.sent();
4193
+ chemicalLookup = _u.sent();
4014
4194
  if (!chemicalLookup) {
4015
4195
  return [2 /*return*/, "continue"];
4016
4196
  }
@@ -4019,7 +4199,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4019
4199
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 3];
4020
4200
  return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'chemical_lookup')];
4021
4201
  case 2:
4022
- fallbackAggregate = _t.sent();
4202
+ fallbackAggregate = _u.sent();
4023
4203
  fallbackDocs = fallbackAggregate.documents;
4024
4204
  if (fallbackDocs.length) {
4025
4205
  documents = fallbackDocs;
@@ -4027,21 +4207,21 @@ function executeAiAssistantMongoAggregate(payload, context) {
4027
4207
  fallbackMeta.chemicalLookup.used = true;
4028
4208
  return [2 /*return*/, "break"];
4029
4209
  }
4030
- _t.label = 3;
4210
+ _u.label = 3;
4031
4211
  case 3: return [2 /*return*/];
4032
4212
  }
4033
4213
  });
4034
4214
  };
4035
4215
  i = 0;
4036
- _s.label = 31;
4216
+ _t.label = 31;
4037
4217
  case 31:
4038
4218
  if (!(i < (executedPipeline || []).length)) return [3 /*break*/, 34];
4039
4219
  return [5 /*yield**/, _loop_1(i)];
4040
4220
  case 32:
4041
- state_1 = _s.sent();
4221
+ state_1 = _t.sent();
4042
4222
  if (state_1 === "break")
4043
4223
  return [3 /*break*/, 34];
4044
- _s.label = 33;
4224
+ _t.label = 33;
4045
4225
  case 33:
4046
4226
  i += 1;
4047
4227
  return [3 /*break*/, 31];
@@ -4064,11 +4244,12 @@ function executeAiAssistantMongoAggregate(payload, context) {
4064
4244
  idClient: normalizedClient,
4065
4245
  idCustomer: customerId,
4066
4246
  isSuperAdmin: isSuperAdmin,
4067
- includeClientScope: shouldScopeByClient
4247
+ includeClientScope: shouldScopeByClient,
4248
+ maxTimeMS: resolveAggregateMaxTimeMS()
4068
4249
  })];
4069
4250
  case 35:
4070
- _f = (_s.sent());
4071
- _s.label = 36;
4251
+ _f = (_t.sent());
4252
+ _t.label = 36;
4072
4253
  case 36:
4073
4254
  probeDocs = _f;
4074
4255
  if (!probeDocs.length) return [3 /*break*/, 38];
@@ -4087,40 +4268,41 @@ function executeAiAssistantMongoAggregate(payload, context) {
4087
4268
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 38];
4088
4269
  return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'query_field_aliases')];
4089
4270
  case 37:
4090
- fallbackAggregate = _s.sent();
4271
+ fallbackAggregate = _t.sent();
4091
4272
  fallbackDocs = fallbackAggregate.documents;
4092
4273
  if (fallbackDocs.length) {
4093
4274
  documents = fallbackDocs;
4094
4275
  executedPipeline = fallbackAggregate.pipeline;
4095
4276
  fallbackMeta.queryFieldAliases.used = true;
4096
4277
  }
4097
- _s.label = 38;
4278
+ _t.label = 38;
4098
4279
  case 38:
4099
4280
  if (!!documents.length) return [3 /*break*/, 42];
4100
4281
  _loop_2 = function (i) {
4101
- var stage, _u, idLookup, rewrittenPipeline, fallbackAggregate, fallbackDocs;
4102
- return __generator(this, function (_v) {
4103
- switch (_v.label) {
4282
+ var stage, _v, idLookup, rewrittenPipeline, fallbackAggregate, fallbackDocs;
4283
+ return __generator(this, function (_w) {
4284
+ switch (_w.label) {
4104
4285
  case 0:
4105
4286
  stage = executedPipeline[i];
4106
4287
  if (!stage || typeof stage !== 'object' || !stage.$match || typeof stage.$match !== 'object') {
4107
4288
  return [2 /*return*/, "continue"];
4108
4289
  }
4109
- _u = probeDocs;
4110
- if (_u) return [3 /*break*/, 2];
4290
+ _v = probeDocs;
4291
+ if (_v) return [3 /*break*/, 2];
4111
4292
  return [4 /*yield*/, fetchAssistantProbeDocs({
4112
4293
  db: db,
4113
4294
  collection: collection,
4114
4295
  idClient: normalizedClient,
4115
4296
  idCustomer: customerId,
4116
4297
  isSuperAdmin: isSuperAdmin,
4117
- includeClientScope: shouldScopeByClient
4298
+ includeClientScope: shouldScopeByClient,
4299
+ maxTimeMS: resolveAggregateMaxTimeMS()
4118
4300
  })];
4119
4301
  case 1:
4120
- _u = (_v.sent());
4121
- _v.label = 2;
4302
+ _v = (_w.sent());
4303
+ _w.label = 2;
4122
4304
  case 2:
4123
- probeDocs = _u;
4305
+ probeDocs = _v;
4124
4306
  return [4 /*yield*/, applyIdLookupFallbackToQuery({
4125
4307
  query: stage.$match,
4126
4308
  db: db,
@@ -4131,7 +4313,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4131
4313
  probeDocs: probeDocs || undefined
4132
4314
  })];
4133
4315
  case 3:
4134
- idLookup = _v.sent();
4316
+ idLookup = _w.sent();
4135
4317
  if (!idLookup) {
4136
4318
  return [2 /*return*/, "continue"];
4137
4319
  }
@@ -4140,7 +4322,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4140
4322
  if (!!containsForbiddenMongoOperators(rewrittenPipeline)) return [3 /*break*/, 5];
4141
4323
  return [4 /*yield*/, runAggregateWithRepair(rewrittenPipeline, 'id_lookup')];
4142
4324
  case 4:
4143
- fallbackAggregate = _v.sent();
4325
+ fallbackAggregate = _w.sent();
4144
4326
  fallbackDocs = fallbackAggregate.documents;
4145
4327
  if (fallbackDocs.length) {
4146
4328
  documents = fallbackDocs;
@@ -4148,26 +4330,26 @@ function executeAiAssistantMongoAggregate(payload, context) {
4148
4330
  fallbackMeta.idLookup.used = true;
4149
4331
  return [2 /*return*/, "break"];
4150
4332
  }
4151
- _v.label = 5;
4333
+ _w.label = 5;
4152
4334
  case 5: return [2 /*return*/];
4153
4335
  }
4154
4336
  });
4155
4337
  };
4156
4338
  i = 0;
4157
- _s.label = 39;
4339
+ _t.label = 39;
4158
4340
  case 39:
4159
4341
  if (!(i < (executedPipeline || []).length)) return [3 /*break*/, 42];
4160
4342
  return [5 /*yield**/, _loop_2(i)];
4161
4343
  case 40:
4162
- state_2 = _s.sent();
4344
+ state_2 = _t.sent();
4163
4345
  if (state_2 === "break")
4164
4346
  return [3 /*break*/, 42];
4165
- _s.label = 41;
4347
+ _t.label = 41;
4166
4348
  case 41:
4167
4349
  i += 1;
4168
4350
  return [3 /*break*/, 39];
4169
4351
  case 42:
4170
- if (!!documents.length) return [3 /*break*/, 53];
4352
+ if (!(!documents.length && hasAggregateRuntimeBudget('relationship_retry'))) return [3 /*break*/, 53];
4171
4353
  return [4 /*yield*/, resolveAssistantNestedAggregateFallbacks({
4172
4354
  db: db,
4173
4355
  dbName: dbName,
@@ -4176,7 +4358,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4176
4358
  triedCollections: triedCollections
4177
4359
  })];
4178
4360
  case 43:
4179
- nestedFallbacks = _s.sent();
4361
+ nestedFallbacks = _t.sent();
4180
4362
  if (!nestedFallbacks.length) return [3 /*break*/, 53];
4181
4363
  fallbackMeta.relationshipRetry = {
4182
4364
  from: collection,
@@ -4189,11 +4371,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
4189
4371
  attempted: true,
4190
4372
  used: false
4191
4373
  };
4192
- _s.label = 44;
4374
+ _t.label = 44;
4193
4375
  case 44:
4194
- _s.trys.push([44, 51, 52, 53]);
4376
+ _t.trys.push([44, 51, 52, 53]);
4195
4377
  nestedFallbacks_1 = __values(nestedFallbacks), nestedFallbacks_1_1 = nestedFallbacks_1.next();
4196
- _s.label = 45;
4378
+ _t.label = 45;
4197
4379
  case 45:
4198
4380
  if (!!nestedFallbacks_1_1.done) return [3 /*break*/, 50];
4199
4381
  nestedFallback = nestedFallbacks_1_1.value;
@@ -4202,12 +4384,12 @@ function executeAiAssistantMongoAggregate(payload, context) {
4202
4384
  rootCollection: retryRootCollection,
4203
4385
  disableCrossCollectionRetry: true
4204
4386
  }) });
4205
- _s.label = 46;
4387
+ _t.label = 46;
4206
4388
  case 46:
4207
- _s.trys.push([46, 48, , 49]);
4389
+ _t.trys.push([46, 48, , 49]);
4208
4390
  return [4 /*yield*/, executeAiAssistantMongoAggregate(fallbackPayload, context)];
4209
4391
  case 47:
4210
- fallbackResult = _s.sent();
4392
+ fallbackResult = _t.sent();
4211
4393
  if (Array.isArray(fallbackResult === null || fallbackResult === void 0 ? void 0 : fallbackResult.documents) && fallbackResult.documents.length) {
4212
4394
  if (canViewDebug && (fallbackResult === null || fallbackResult === void 0 ? void 0 : fallbackResult.debug) && typeof fallbackResult.debug === 'object') {
4213
4395
  existingFallbacks = fallbackResult.debug.fallbacks && typeof fallbackResult.debug.fallbacks === 'object'
@@ -4226,7 +4408,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4226
4408
  }
4227
4409
  return [3 /*break*/, 49];
4228
4410
  case 48:
4229
- error_7 = _s.sent();
4411
+ error_7 = _t.sent();
4230
4412
  errorMessage = normalizeOptionalString(error_7 === null || error_7 === void 0 ? void 0 : error_7.message) || 'Unknown error';
4231
4413
  existingErrors = Array.isArray(fallbackMeta.relationshipRetry.errors)
4232
4414
  ? fallbackMeta.relationshipRetry.errors
@@ -4242,20 +4424,20 @@ function executeAiAssistantMongoAggregate(payload, context) {
4242
4424
  return [3 /*break*/, 45];
4243
4425
  case 50: return [3 /*break*/, 53];
4244
4426
  case 51:
4245
- e_2_1 = _s.sent();
4427
+ e_2_1 = _t.sent();
4246
4428
  e_2 = { error: e_2_1 };
4247
4429
  return [3 /*break*/, 53];
4248
4430
  case 52:
4249
4431
  try {
4250
- if (nestedFallbacks_1_1 && !nestedFallbacks_1_1.done && (_o = nestedFallbacks_1.return)) _o.call(nestedFallbacks_1);
4432
+ if (nestedFallbacks_1_1 && !nestedFallbacks_1_1.done && (_p = nestedFallbacks_1.return)) _p.call(nestedFallbacks_1);
4251
4433
  }
4252
4434
  finally { if (e_2) throw e_2.error; }
4253
4435
  return [7 /*endfinally*/];
4254
4436
  case 53:
4255
- if (!!documents.length) return [3 /*break*/, 56];
4437
+ if (!(!documents.length && hasAggregateRuntimeBudget('report_fallback'))) return [3 /*break*/, 56];
4256
4438
  return [4 /*yield*/, resolveBaseCollectionFromReport(db, dbName, collection)];
4257
4439
  case 54:
4258
- baseCollection = _s.sent();
4440
+ baseCollection = _t.sent();
4259
4441
  if (!(baseCollection && baseCollection !== collection)) return [3 /*break*/, 56];
4260
4442
  addAssistantCollectionToTriedSet(triedCollections, baseCollection);
4261
4443
  fallbackPayload = __assign(__assign({}, input), { collection: baseCollection, __assistantRetryState: buildAssistantRetryState(retryState, triedCollections, {
@@ -4263,7 +4445,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4263
4445
  }) });
4264
4446
  return [4 /*yield*/, executeAiAssistantMongoAggregate(fallbackPayload, context)];
4265
4447
  case 55:
4266
- fallbackResult = _s.sent();
4448
+ fallbackResult = _t.sent();
4267
4449
  if (Array.isArray(fallbackResult === null || fallbackResult === void 0 ? void 0 : fallbackResult.documents) && fallbackResult.documents.length) {
4268
4450
  if (canViewDebug && (fallbackResult === null || fallbackResult === void 0 ? void 0 : fallbackResult.debug) && typeof fallbackResult.debug === 'object') {
4269
4451
  existingFallbacks = fallbackResult.debug.fallbacks && typeof fallbackResult.debug.fallbacks === 'object'
@@ -4280,15 +4462,15 @@ function executeAiAssistantMongoAggregate(payload, context) {
4280
4462
  if (canViewDebug) {
4281
4463
  fallbackMeta.reportFallback = { from: collection, to: baseCollection, attempted: true, used: false };
4282
4464
  }
4283
- _s.label = 56;
4465
+ _t.label = 56;
4284
4466
  case 56:
4285
- if (!(!documents.length && crossCollectionRetryEnabled)) return [3 /*break*/, 67];
4467
+ if (!(!documents.length && crossCollectionRetryEnabled && hasAggregateRuntimeBudget('collection_retry'))) return [3 /*break*/, 67];
4286
4468
  fallbackAcceptanceOptions = buildAssistantAggregateFallbackAcceptanceOptions(executedPipeline || []);
4287
4469
  return [4 /*yield*/, resolveAssistantAvailableCrossCollectionFallbacks(db, dbName, collection, triedCollections, {
4288
4470
  fieldHints: collectAggregateReferencedFieldPaths(executedPipeline || [])
4289
4471
  })];
4290
4472
  case 57:
4291
- crossCollectionCandidates = _s.sent();
4473
+ crossCollectionCandidates = _t.sent();
4292
4474
  if (!crossCollectionCandidates.length) return [3 /*break*/, 67];
4293
4475
  fallbackMeta.collectionRetry = {
4294
4476
  from: collection,
@@ -4297,11 +4479,11 @@ function executeAiAssistantMongoAggregate(payload, context) {
4297
4479
  attempted: true,
4298
4480
  used: false
4299
4481
  };
4300
- _s.label = 58;
4482
+ _t.label = 58;
4301
4483
  case 58:
4302
- _s.trys.push([58, 65, 66, 67]);
4484
+ _t.trys.push([58, 65, 66, 67]);
4303
4485
  crossCollectionCandidates_2 = __values(crossCollectionCandidates), crossCollectionCandidates_2_1 = crossCollectionCandidates_2.next();
4304
- _s.label = 59;
4486
+ _t.label = 59;
4305
4487
  case 59:
4306
4488
  if (!!crossCollectionCandidates_2_1.done) return [3 /*break*/, 64];
4307
4489
  candidateCollection = crossCollectionCandidates_2_1.value;
@@ -4310,12 +4492,12 @@ function executeAiAssistantMongoAggregate(payload, context) {
4310
4492
  rootCollection: retryRootCollection,
4311
4493
  disableCrossCollectionRetry: true
4312
4494
  }) });
4313
- _s.label = 60;
4495
+ _t.label = 60;
4314
4496
  case 60:
4315
- _s.trys.push([60, 62, , 63]);
4497
+ _t.trys.push([60, 62, , 63]);
4316
4498
  return [4 /*yield*/, executeAiAssistantMongoAggregate(fallbackPayload, context)];
4317
4499
  case 61:
4318
- fallbackResult = _s.sent();
4500
+ fallbackResult = _t.sent();
4319
4501
  fallbackDocs = Array.isArray(fallbackResult === null || fallbackResult === void 0 ? void 0 : fallbackResult.documents) ? fallbackResult.documents : [];
4320
4502
  fallbackQuality = evaluateAssistantFallbackDocumentsQuality(fallbackDocs, fallbackAcceptanceOptions);
4321
4503
  if (fallbackDocs.length && fallbackQuality.accepted) {
@@ -4350,7 +4532,7 @@ function executeAiAssistantMongoAggregate(payload, context) {
4350
4532
  }
4351
4533
  return [3 /*break*/, 63];
4352
4534
  case 62:
4353
- error_8 = _s.sent();
4535
+ error_8 = _t.sent();
4354
4536
  if (fallbackMeta.collectionRetry && typeof fallbackMeta.collectionRetry === 'object') {
4355
4537
  existingErrors = Array.isArray(fallbackMeta.collectionRetry.errors)
4356
4538
  ? fallbackMeta.collectionRetry.errors
@@ -4367,17 +4549,17 @@ function executeAiAssistantMongoAggregate(payload, context) {
4367
4549
  return [3 /*break*/, 59];
4368
4550
  case 64: return [3 /*break*/, 67];
4369
4551
  case 65:
4370
- e_3_1 = _s.sent();
4552
+ e_3_1 = _t.sent();
4371
4553
  e_3 = { error: e_3_1 };
4372
4554
  return [3 /*break*/, 67];
4373
4555
  case 66:
4374
4556
  try {
4375
- if (crossCollectionCandidates_2_1 && !crossCollectionCandidates_2_1.done && (_p = crossCollectionCandidates_2.return)) _p.call(crossCollectionCandidates_2);
4557
+ if (crossCollectionCandidates_2_1 && !crossCollectionCandidates_2_1.done && (_q = crossCollectionCandidates_2.return)) _q.call(crossCollectionCandidates_2);
4376
4558
  }
4377
4559
  finally { if (e_3) throw e_3.error; }
4378
4560
  return [7 /*endfinally*/];
4379
4561
  case 67:
4380
- if (!(!documents.length && canViewDebug)) return [3 /*break*/, 84];
4562
+ if (!(!documents.length && canViewDebug && hasAggregateRuntimeBudget('zero_diagnostics', 20))) return [3 /*break*/, 84];
4381
4563
  matchStages = (executedPipeline || []).filter(function (stage) { return stage && typeof stage === 'object' && stage.$match && typeof stage.$match === 'object'; });
4382
4564
  diagnostics = {};
4383
4565
  if (!matchStages.length) return [3 /*break*/, 84];
@@ -4387,34 +4569,31 @@ function executeAiAssistantMongoAggregate(payload, context) {
4387
4569
  dateFields = collectMatchFieldsByCondition(combinedMatch, function (_field, condition) { return isDateCondition(condition); });
4388
4570
  diagnostics.nameFields = nameFields.length ? nameFields : undefined;
4389
4571
  diagnostics.dateFields = dateFields.length ? dateFields : undefined;
4390
- _s.label = 68;
4572
+ _t.label = 68;
4391
4573
  case 68:
4392
- _s.trys.push([68, 73, , 74]);
4574
+ _t.trys.push([68, 73, , 74]);
4575
+ countOptions = buildAggregateCountOptions();
4393
4576
  if (!nameFields.length) return [3 /*break*/, 70];
4394
4577
  queryNoName = stripMatchFields(combinedMatch, nameFields);
4395
4578
  _g = diagnostics;
4396
- return [4 /*yield*/, db.collection(collection).countDocuments(queryNoName, {
4397
- readPreference: AI_ASSISTANT_READ_PREFERENCE
4398
- })];
4579
+ return [4 /*yield*/, db.collection(collection).countDocuments(queryNoName, countOptions)];
4399
4580
  case 69:
4400
- _g.recentCount = _s.sent();
4401
- _s.label = 70;
4581
+ _g.recentCount = _t.sent();
4582
+ _t.label = 70;
4402
4583
  case 70:
4403
4584
  if (!dateFields.length) return [3 /*break*/, 72];
4404
4585
  queryNoDate = stripMatchFields(combinedMatch, dateFields);
4405
4586
  _h = diagnostics;
4406
- return [4 /*yield*/, db.collection(collection).countDocuments(queryNoDate, {
4407
- readPreference: AI_ASSISTANT_READ_PREFERENCE
4408
- })];
4587
+ return [4 /*yield*/, db.collection(collection).countDocuments(queryNoDate, countOptions)];
4409
4588
  case 71:
4410
- _h.nameMatchCount = _s.sent();
4411
- _s.label = 72;
4589
+ _h.nameMatchCount = _t.sent();
4590
+ _t.label = 72;
4412
4591
  case 72: return [3 /*break*/, 74];
4413
4592
  case 73:
4414
- _j = _s.sent();
4593
+ _j = _t.sent();
4415
4594
  return [3 /*break*/, 74];
4416
4595
  case 74:
4417
- _s.trys.push([74, 77, , 78]);
4596
+ _t.trys.push([74, 77, , 78]);
4418
4597
  _k = probeDocs;
4419
4598
  if (_k) return [3 /*break*/, 76];
4420
4599
  return [4 /*yield*/, fetchAssistantProbeDocs({
@@ -4423,11 +4602,12 @@ function executeAiAssistantMongoAggregate(payload, context) {
4423
4602
  idClient: normalizedClient,
4424
4603
  idCustomer: customerId,
4425
4604
  isSuperAdmin: isSuperAdmin,
4426
- includeClientScope: shouldScopeByClient
4605
+ includeClientScope: shouldScopeByClient,
4606
+ maxTimeMS: resolveAggregateMaxTimeMS()
4427
4607
  })];
4428
4608
  case 75:
4429
- _k = (_s.sent());
4430
- _s.label = 76;
4609
+ _k = (_t.sent());
4610
+ _t.label = 76;
4431
4611
  case 76:
4432
4612
  probeDocs = _k;
4433
4613
  if (probeDocs.length && nameFields.length) {
@@ -4435,42 +4615,50 @@ function executeAiAssistantMongoAggregate(payload, context) {
4435
4615
  }
4436
4616
  return [3 /*break*/, 78];
4437
4617
  case 77:
4438
- _l = _s.sent();
4618
+ _l = _t.sent();
4439
4619
  return [3 /*break*/, 78];
4440
4620
  case 78:
4441
- _s.trys.push([78, 82, , 83]);
4621
+ _t.trys.push([78, 82, , 83]);
4442
4622
  return [4 /*yield*/, listAssistantCollections(db, dbName)];
4443
4623
  case 79:
4444
- allCollections = _s.sent();
4624
+ allCollections = _t.sent();
4445
4625
  base = stripVersionSuffix(collection.startsWith('report-') ? collection.slice('report-'.length) : collection);
4446
4626
  alt = collection.startsWith('report-') ? base : "report-".concat(base);
4447
4627
  if (!(alt && alt !== collection && allCollections.includes(alt))) return [3 /*break*/, 81];
4448
- return [4 /*yield*/, db.collection(alt).countDocuments({}, { readPreference: AI_ASSISTANT_READ_PREFERENCE })];
4628
+ return [4 /*yield*/, db.collection(alt).countDocuments({}, buildAggregateCountOptions())];
4449
4629
  case 80:
4450
- altCount = _s.sent();
4630
+ altCount = _t.sent();
4451
4631
  diagnostics.alternateCollection = alt;
4452
4632
  diagnostics.alternateCollectionCount = altCount;
4453
- _s.label = 81;
4633
+ _t.label = 81;
4454
4634
  case 81: return [3 /*break*/, 83];
4455
4635
  case 82:
4456
- _m = _s.sent();
4636
+ _m = _t.sent();
4457
4637
  return [3 /*break*/, 83];
4458
4638
  case 83:
4459
4639
  fallbackMeta.zeroDiagnostics = diagnostics;
4460
- _s.label = 84;
4461
- case 84: return [4 /*yield*/, verifyAssistantAggregateReliability({
4462
- db: db,
4463
- collection: collection,
4464
- pipeline: executedPipeline,
4465
- documents: documents,
4466
- aggregateOptions: aggregateOptions
4467
- })];
4640
+ _t.label = 84;
4641
+ case 84:
4642
+ if (!hasAggregateRuntimeBudget('verification', 40)) return [3 /*break*/, 86];
4643
+ return [4 /*yield*/, verifyAssistantAggregateReliability({
4644
+ db: db,
4645
+ collection: collection,
4646
+ pipeline: executedPipeline,
4647
+ documents: documents,
4648
+ aggregateOptions: buildAggregateOptions()
4649
+ })];
4468
4650
  case 85:
4469
- verification = _s.sent();
4651
+ _o = _t.sent();
4652
+ return [3 /*break*/, 87];
4653
+ case 86:
4654
+ _o = null;
4655
+ _t.label = 87;
4656
+ case 87:
4657
+ verification = _o;
4470
4658
  sanitizedDocuments = isSuperAdmin
4471
4659
  ? documents
4472
4660
  : documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
4473
- includeIds = ((_r = input.options) === null || _r === void 0 ? void 0 : _r.includeIds) === true;
4661
+ includeIds = ((_s = input.options) === null || _s === void 0 ? void 0 : _s.includeIds) === true;
4474
4662
  displayDocs = sanitizedDocuments.map(function (doc) { return flattenForTable(doc, {
4475
4663
  includeGroupFromId: true,
4476
4664
  includeIds: true
@@ -4484,8 +4672,8 @@ function executeAiAssistantMongoAggregate(payload, context) {
4484
4672
  idCustomer: customerId,
4485
4673
  isSuperAdmin: isSuperAdmin
4486
4674
  })];
4487
- case 86:
4488
- idLookupDisplay = _s.sent();
4675
+ case 88:
4676
+ idLookupDisplay = _t.sent();
4489
4677
  if (idLookupDisplay === null || idLookupDisplay === void 0 ? void 0 : idLookupDisplay.docs) {
4490
4678
  displayDocs = idLookupDisplay.docs;
4491
4679
  }
@@ -7930,6 +8118,9 @@ function buildAssistantCodexErrorMessage(error) {
7930
8118
  }
7931
8119
  return 'I ran into an internal error while preparing that response. Please try again.';
7932
8120
  }
8121
+ function buildAssistantRunBudgetExceededMessage() {
8122
+ return 'I could not finish this request within the assistant time budget. Please narrow the date range or ask for a smaller slice of data and retry.';
8123
+ }
7933
8124
  function isAssistantIdField(key) {
7934
8125
  var normalized = String(key || '').trim().toLowerCase();
7935
8126
  if (!normalized) {
@@ -16503,13 +16694,13 @@ function buildAssistantProbeQuery(collection, idClient, idCustomer, isSuperAdmin
16503
16694
  return applyCustomerScopeFilter(query, collection, idCustomer, isSuperAdmin);
16504
16695
  }
16505
16696
  function fetchAssistantProbeDocs(params) {
16506
- var db = params.db, collection = params.collection, idClient = params.idClient, idCustomer = params.idCustomer, isSuperAdmin = params.isSuperAdmin, includeClientScope = params.includeClientScope;
16697
+ var db = params.db, collection = params.collection, idClient = params.idClient, idCustomer = params.idCustomer, isSuperAdmin = params.isSuperAdmin, includeClientScope = params.includeClientScope, maxTimeMS = params.maxTimeMS;
16507
16698
  var probeQuery = buildAssistantProbeQuery(collection, idClient, idCustomer, isSuperAdmin, includeClientScope);
16699
+ var resolvedMaxTimeMS = resolveAssistantEffectiveMongoMaxTimeMs({
16700
+ requestedMaxTimeMS: maxTimeMS
16701
+ });
16508
16702
  return db.collection(collection)
16509
- .find(probeQuery, {
16510
- limit: AI_ASSISTANT_PROBE_LIMIT,
16511
- readPreference: AI_ASSISTANT_READ_PREFERENCE
16512
- })
16703
+ .find(probeQuery, __assign({ limit: AI_ASSISTANT_PROBE_LIMIT, readPreference: AI_ASSISTANT_READ_PREFERENCE }, (resolvedMaxTimeMS ? { maxTimeMS: resolvedMaxTimeMS } : {})))
16513
16704
  .toArray();
16514
16705
  }
16515
16706
  var AI_ASSISTANT_PERMISSION_ACTION_TOKENS = new Set([
@@ -16778,6 +16969,84 @@ function resolveCodexTimeoutMs() {
16778
16969
  }
16779
16970
  return DEFAULT_CODEX_TIMEOUT_MS;
16780
16971
  }
16972
+ function resolveAssistantFastModeEnabled() {
16973
+ var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
16974
+ var raw = normalizeOptionalBoolean(config['AI_ASSISTANT_FAST_MODE_ENABLED']
16975
+ || process.env.AI_ASSISTANT_FAST_MODE_ENABLED);
16976
+ return raw === undefined ? true : raw === true;
16977
+ }
16978
+ function resolveAssistantRunBudgetMs() {
16979
+ var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
16980
+ var raw = normalizeOptionalNumber(config['AI_ASSISTANT_RUN_BUDGET_MS']
16981
+ || process.env.AI_ASSISTANT_RUN_BUDGET_MS);
16982
+ if (raw && raw > 0) {
16983
+ return Math.max((0, common_1.round)(raw), 5000);
16984
+ }
16985
+ return DEFAULT_AI_ASSISTANT_RUN_BUDGET_MS;
16986
+ }
16987
+ function resolveAssistantMongoDefaultMaxTimeMs() {
16988
+ var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
16989
+ var raw = normalizeOptionalNumber(config['AI_ASSISTANT_MONGO_MAX_TIME_MS']
16990
+ || process.env.AI_ASSISTANT_MONGO_MAX_TIME_MS);
16991
+ if (raw && raw > 0) {
16992
+ return Math.max((0, common_1.round)(raw), 250);
16993
+ }
16994
+ return DEFAULT_AI_ASSISTANT_MONGO_MAX_TIME_MS;
16995
+ }
16996
+ function normalizeAssistantRuntimeControl(value) {
16997
+ if (!value || typeof value !== 'object') {
16998
+ return null;
16999
+ }
17000
+ var deadlineRaw = normalizeOptionalNumber(value.deadlineMs);
17001
+ var maxTimeRaw = normalizeOptionalNumber(value.maxTimeMS);
17002
+ var fastModeRaw = normalizeOptionalBoolean(value.fastMode);
17003
+ var next = {};
17004
+ if (deadlineRaw && deadlineRaw > 0) {
17005
+ next.deadlineMs = (0, common_1.round)(deadlineRaw);
17006
+ }
17007
+ if (maxTimeRaw && maxTimeRaw > 0) {
17008
+ next.maxTimeMS = (0, common_1.round)(maxTimeRaw);
17009
+ }
17010
+ if (typeof fastModeRaw === 'boolean') {
17011
+ next.fastMode = fastModeRaw;
17012
+ }
17013
+ return Object.keys(next).length ? next : null;
17014
+ }
17015
+ function resolveAssistantRuntimeRemainingMs(runtime) {
17016
+ var deadline = normalizeOptionalNumber(runtime === null || runtime === void 0 ? void 0 : runtime.deadlineMs);
17017
+ if (!deadline || deadline <= 0) {
17018
+ return null;
17019
+ }
17020
+ return Math.max((0, common_1.round)(deadline) - Date.now(), 0);
17021
+ }
17022
+ function hasAssistantRuntimeBudget(runtime, minimumMs) {
17023
+ if (minimumMs === void 0) { minimumMs = AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS; }
17024
+ var remaining = resolveAssistantRuntimeRemainingMs(runtime);
17025
+ if (remaining === null) {
17026
+ return true;
17027
+ }
17028
+ return remaining >= Math.max((0, common_1.round)(minimumMs || 0), 1);
17029
+ }
17030
+ function resolveAssistantEffectiveMongoMaxTimeMs(params) {
17031
+ var _a;
17032
+ var requested = normalizeOptionalNumber(params === null || params === void 0 ? void 0 : params.requestedMaxTimeMS);
17033
+ var runtimeMax = normalizeOptionalNumber((_a = params === null || params === void 0 ? void 0 : params.runtime) === null || _a === void 0 ? void 0 : _a.maxTimeMS);
17034
+ var configured = resolveAssistantMongoDefaultMaxTimeMs();
17035
+ var resolved = requested && requested > 0
17036
+ ? (0, common_1.round)(requested)
17037
+ : configured;
17038
+ if (runtimeMax && runtimeMax > 0) {
17039
+ resolved = Math.min(resolved, (0, common_1.round)(runtimeMax));
17040
+ }
17041
+ var remaining = resolveAssistantRuntimeRemainingMs((params === null || params === void 0 ? void 0 : params.runtime) || null);
17042
+ if (remaining !== null) {
17043
+ if (remaining < AI_ASSISTANT_MONGO_MIN_STAGE_BUDGET_MS) {
17044
+ return undefined;
17045
+ }
17046
+ resolved = Math.min(resolved, remaining);
17047
+ }
17048
+ return resolved > 0 ? Math.max((0, common_1.round)(resolved), 50) : undefined;
17049
+ }
16781
17050
  function resolveCodexWorkerThreadEnabled() {
16782
17051
  var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
16783
17052
  var raw = normalizeOptionalString(config['AI_ASSISTANT_CODEX_USE_WORKER_THREAD']
@@ -16892,7 +17161,7 @@ function resolveCodexSettings(options) {
16892
17161
  var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
16893
17162
  var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
16894
17163
  if (!apiKey) {
16895
- throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
17164
+ throw new Error('AI API key missing. Add an AI API key to server config.');
16896
17165
  }
16897
17166
  var model = normalizeOptionalString(options === null || options === void 0 ? void 0 : options.model) || resolveCodexModel();
16898
17167
  var fallbackModels = resolveCodexFallbackModels({ fallbackModels: options === null || options === void 0 ? void 0 : options.fallbackModels }, model);
@@ -17001,7 +17270,7 @@ function waitForCodexWorkerMessage(worker, streamStatusHandler) {
17001
17270
  if (e_44) throw e_44.error;
17002
17271
  return [7 /*endfinally*/];
17003
17272
  case 10: return [7 /*endfinally*/];
17004
- case 11: throw new CodexWorkerBootstrapError('Codex worker exited before completing.');
17273
+ case 11: throw new CodexWorkerBootstrapError('AI worker exited before completing.');
17005
17274
  }
17006
17275
  });
17007
17276
  });
@@ -17040,7 +17309,7 @@ function runCodexInWorkerThread(prompt, runOptions, config, streamStatusHandler)
17040
17309
  if (!(error_10 instanceof CodexWorkerBootstrapError)) {
17041
17310
  throw error_10;
17042
17311
  }
17043
- console.error('Codex worker bootstrap failed, falling back to in-process run.', error_10);
17312
+ console.error('AI worker bootstrap failed, falling back to in-process run.', error_10);
17044
17313
  codexClient = getAssistantCodexClient(config);
17045
17314
  return [4 /*yield*/, codexClient.run(prompt, streamedOptions)];
17046
17315
  case 10: return [2 /*return*/, _a.sent()];
@@ -17069,7 +17338,7 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config,
17069
17338
  });
17070
17339
  }
17071
17340
  catch (error) {
17072
- wrapped = new CodexWorkerBootstrapError('Failed to start codex worker.');
17341
+ wrapped = new CodexWorkerBootstrapError('Failed to start AI worker.');
17073
17342
  if (error instanceof Error && error.stack) {
17074
17343
  wrapped.stack = error.stack;
17075
17344
  }
@@ -17150,28 +17419,28 @@ function runCodexInWorkerThreadInternal(workerPath, prompt, runOptions, config,
17150
17419
  if (outcome.message && outcome.message.ok) {
17151
17420
  return [2 /*return*/, outcome.message.result || ''];
17152
17421
  }
17153
- throw new Error(((_a = outcome.message) === null || _a === void 0 ? void 0 : _a.error) || 'Codex worker failed.');
17422
+ throw new Error(((_a = outcome.message) === null || _a === void 0 ? void 0 : _a.error) || 'AI worker failed.');
17154
17423
  case 6:
17155
17424
  if (!(outcome.type === 'timeout')) return [3 /*break*/, 8];
17156
17425
  return [4 /*yield*/, terminateWorker(worker)];
17157
17426
  case 7:
17158
17427
  _c.sent();
17159
- throw new CodexWorkerBootstrapError('Codex worker timed out.');
17428
+ throw new CodexWorkerBootstrapError('AI worker timed out.');
17160
17429
  case 8:
17161
17430
  if (!(outcome.type === 'error')) return [3 /*break*/, 10];
17162
17431
  return [4 /*yield*/, terminateWorker(worker)];
17163
17432
  case 9:
17164
17433
  _c.sent();
17165
- wrapped = new CodexWorkerBootstrapError('Codex worker errored before completing.');
17434
+ wrapped = new CodexWorkerBootstrapError('AI worker errored before completing.');
17166
17435
  if ((_b = outcome.error) === null || _b === void 0 ? void 0 : _b.stack) {
17167
17436
  wrapped.stack = outcome.error.stack;
17168
17437
  }
17169
17438
  throw wrapped;
17170
17439
  case 10:
17171
17440
  if (outcome.type === 'exit') {
17172
- throw new CodexWorkerBootstrapError("Codex worker exited before completing (code ".concat(outcome.code, ")."));
17441
+ throw new CodexWorkerBootstrapError("AI worker exited before completing (code ".concat(outcome.code, ")."));
17173
17442
  }
17174
- throw new CodexWorkerBootstrapError('Codex worker aborted before completing.');
17443
+ throw new CodexWorkerBootstrapError('AI worker aborted before completing.');
17175
17444
  }
17176
17445
  });
17177
17446
  });
@@ -19959,22 +20228,6 @@ function evaluateAssistantGuardrails(message) {
19959
20228
  }
19960
20229
  return null;
19961
20230
  }
19962
- function resolveOpenAISettings(config) {
19963
- var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
19964
- var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
19965
- if (!apiKey) {
19966
- throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
19967
- }
19968
- return {
19969
- apiKey: apiKey,
19970
- baseUrl: (serverConfig['OPENAI_BASE_URL'] || process.env.OPENAI_BASE_URL || '').trim() || undefined,
19971
- model: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.model) || (serverConfig['OPENAI_MODEL'] || process.env.OPENAI_MODEL || 'gpt-5.1').trim(),
19972
- temperature: normalizeOptionalNumber(config === null || config === void 0 ? void 0 : config.temperature),
19973
- maxTokens: normalizeOptionalNumber(config === null || config === void 0 ? void 0 : config.max_tokens),
19974
- maxRetries: normalizeOptionalNumber(serverConfig['OPENAI_MAX_RETRIES'] || process.env.OPENAI_MAX_RETRIES),
19975
- retryDelayMs: normalizeOptionalNumber(serverConfig['OPENAI_RETRY_DELAY_MS'] || process.env.OPENAI_RETRY_DELAY_MS)
19976
- };
19977
- }
19978
20231
  function buildAiFormSystemPrompt() {
19979
20232
  return AI_FORM_PATCH_SYSTEM_PROMPT;
19980
20233
  }
@@ -20481,6 +20734,29 @@ function buildUserPrompt(template, inputText, attachmentText) {
20481
20734
  }
20482
20735
  return "".concat(inputText || '').concat(attachmentText).trim();
20483
20736
  }
20737
+ function buildCodexChatPrompt(messages) {
20738
+ var systemParts = [];
20739
+ var dialogParts = [];
20740
+ (messages || []).forEach(function (message) {
20741
+ var content = normalizeOptionalString(message === null || message === void 0 ? void 0 : message.content);
20742
+ if (!content) {
20743
+ return;
20744
+ }
20745
+ if (message.role === 'system') {
20746
+ systemParts.push(content);
20747
+ return;
20748
+ }
20749
+ var label = message.role === 'assistant' ? 'Assistant' : 'User';
20750
+ dialogParts.push("".concat(label, ":\n").concat(content));
20751
+ });
20752
+ var systemPrompt = systemParts.length
20753
+ ? systemParts.join('\n\n')
20754
+ : 'You are a helpful AI assistant.';
20755
+ var dialogPrompt = dialogParts.length
20756
+ ? dialogParts.join('\n\n')
20757
+ : 'User:\nContinue.';
20758
+ return "System:\n".concat(systemPrompt, "\n\n").concat(dialogPrompt).trim();
20759
+ }
20484
20760
  function applyTemplate(template, data) {
20485
20761
  var output = template;
20486
20762
  Object.keys(data).forEach(function (key) {
@@ -20491,9 +20767,17 @@ function applyTemplate(template, data) {
20491
20767
  return output;
20492
20768
  }
20493
20769
  function sanitizeConfig(source) {
20770
+ var fallbackModels = Array.isArray(source === null || source === void 0 ? void 0 : source.fallback_models)
20771
+ ? source.fallback_models
20772
+ : (Array.isArray(source === null || source === void 0 ? void 0 : source.fallbackModels) ? source.fallbackModels : []);
20494
20773
  return {
20495
20774
  mode: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.mode),
20496
20775
  model: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.model),
20776
+ codex_model: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.codex_model),
20777
+ fallback_model: normalizeOptionalString((source === null || source === void 0 ? void 0 : source.fallback_model) || (source === null || source === void 0 ? void 0 : source.fallbackModel)),
20778
+ fallback_models: fallbackModels
20779
+ .map(function (entry) { return normalizeOptionalString(entry); })
20780
+ .filter(Boolean),
20497
20781
  system_prompt: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.system_prompt),
20498
20782
  user_prompt_template: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.user_prompt_template),
20499
20783
  response_format: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.response_format),