@oneuptime/common 11.5.4 → 11.5.5

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.
Files changed (505) hide show
  1. package/Models/DatabaseModels/AIAgentTaskPullRequest.ts +56 -45
  2. package/Models/DatabaseModels/AIInsight.ts +748 -0
  3. package/Models/DatabaseModels/AIRun.ts +262 -0
  4. package/Models/DatabaseModels/CodeRepository.ts +42 -0
  5. package/Models/DatabaseModels/GlobalConfig.ts +105 -0
  6. package/Models/DatabaseModels/Index.ts +4 -8
  7. package/Models/DatabaseModels/InstanceHealthLog.ts +277 -0
  8. package/Models/DatabaseModels/LlmLog.ts +33 -0
  9. package/Models/DatabaseModels/Project.ts +123 -6
  10. package/Models/DatabaseModels/Runbook.ts +1 -1
  11. package/Server/API/AIAgentDataAPI.ts +802 -140
  12. package/Server/API/AIAgentTaskAPI.ts +132 -69
  13. package/Server/API/AIAgentTaskLogAPI.ts +65 -41
  14. package/Server/API/AIAgentTaskPullRequestAPI.ts +41 -0
  15. package/Server/API/AIInsightAPI.ts +220 -0
  16. package/Server/API/AIInvestigationAPI.ts +363 -1
  17. package/Server/API/CodeFixRunAPI.ts +251 -0
  18. package/Server/API/GitHubAPI.ts +246 -3
  19. package/Server/API/TelemetryExceptionAPI.ts +193 -48
  20. package/Server/EnvironmentConfig.ts +1 -1
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.ts +26 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.ts +73 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.ts +29 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.ts +31 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.ts +51 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.ts +25 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.ts +47 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.ts +53 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.ts +31 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.ts +37 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.ts +25 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.ts +75 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.ts +37 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.ts +203 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.ts +163 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +30 -0
  37. package/Server/Infrastructure/Queue.ts +82 -4
  38. package/Server/Infrastructure/Semaphore.ts +62 -1
  39. package/Server/Services/AIAgentService.ts +32 -0
  40. package/Server/Services/AIAgentTaskPullRequestService.ts +117 -0
  41. package/Server/Services/AIInsightService.ts +174 -0
  42. package/Server/Services/AIRunEventService.ts +63 -0
  43. package/Server/Services/AIRunService.ts +259 -1
  44. package/Server/Services/AIService.ts +249 -7
  45. package/Server/Services/AlertService.ts +4 -4
  46. package/Server/Services/CodeRepositoryService.ts +209 -0
  47. package/Server/Services/GlobalConfigService.ts +148 -0
  48. package/Server/Services/IncidentService.ts +183 -38
  49. package/Server/Services/IncidentStateTimelineService.ts +24 -4
  50. package/Server/Services/Index.ts +4 -4
  51. package/Server/Services/{AIAgentTaskLogService.ts → InstanceHealthLogService.ts} +1 -1
  52. package/Server/Services/LlmLogService.ts +27 -0
  53. package/Server/Services/LlmProviderService.ts +108 -0
  54. package/Server/Services/MetricBaselineService.ts +123 -0
  55. package/Server/Services/MonitorService.ts +15 -0
  56. package/Server/Services/TelemetryExceptionService.ts +323 -116
  57. package/Server/Services/TraceAggregationService.ts +176 -0
  58. package/Server/Types/Workflow/ComponentCode.ts +6 -0
  59. package/Server/Types/Workflow/Components/AI/GenerateText.ts +326 -0
  60. package/Server/Types/Workflow/Components/Index.ts +2 -0
  61. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +1 -1
  62. package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +71 -0
  63. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +243 -0
  64. package/Server/Utils/AI/CodeFix/CodeFixRunQueue.ts +131 -0
  65. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +148 -0
  66. package/Server/Utils/AI/CodeFix/OpenPullRequestCap.ts +117 -0
  67. package/Server/Utils/AI/Eval/EvalCorpus.ts +369 -0
  68. package/Server/Utils/AI/Eval/EvalScores.ts +172 -0
  69. package/Server/Utils/AI/Eval/ReplayInvestigation.ts +87 -0
  70. package/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.ts +676 -0
  71. package/Server/Utils/AI/{Sentinel/SentinelInvestigationEngine.ts → SRE/AIInvestigationEngine.ts} +58 -37
  72. package/Server/Utils/AI/{Sentinel/SentinelMemory.ts → SRE/AIMemory.ts} +3 -3
  73. package/Server/Utils/AI/{Sentinel → SRE}/AlertInvestigationRunner.ts +50 -20
  74. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +293 -0
  75. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +115 -0
  76. package/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.ts +223 -0
  77. package/Server/Utils/AI/{Sentinel → SRE}/IncidentInvestigationRunner.ts +71 -21
  78. package/Server/Utils/AI/{Sentinel → SRE}/IncidentPostmortemRunner.ts +8 -8
  79. package/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.ts +364 -0
  80. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +317 -0
  81. package/Server/Utils/AI/SRE/Insights/Detectors/Index.ts +27 -0
  82. package/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.ts +221 -0
  83. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +238 -0
  84. package/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.ts +521 -0
  85. package/Server/Utils/AI/SRE/Insights/FixRouting.ts +242 -0
  86. package/Server/Utils/AI/SRE/Insights/InsightScanner.ts +290 -0
  87. package/Server/Utils/AI/SRE/Insights/InsightStore.ts +283 -0
  88. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +242 -0
  89. package/Server/Utils/AI/SRE/Insights/Triage.ts +162 -0
  90. package/Server/Utils/AI/SRE/Insights/Types.ts +49 -0
  91. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +212 -0
  92. package/Server/Utils/AI/SRE/InvestigationGrader.ts +282 -0
  93. package/Server/Utils/AI/{Sentinel → SRE}/InvestigationQueue.ts +114 -19
  94. package/Server/Utils/AI/{Sentinel → SRE}/README.md +4 -4
  95. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +172 -0
  96. package/Server/Utils/AI/Toolbox/{SentinelActionTools.ts → AIActionTools.ts} +22 -1
  97. package/Server/Utils/AI/Toolbox/Index.ts +2 -2
  98. package/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.ts +526 -0
  99. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +319 -1
  100. package/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.ts +221 -0
  101. package/Server/Utils/CodeRepository/StackTraceRepoResolver.ts +571 -0
  102. package/Server/Utils/Execute.ts +2 -1
  103. package/Server/Utils/LLM/LLMService.ts +160 -30
  104. package/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.ts +152 -0
  105. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +29 -0
  106. package/Tests/Server/Infrastructure/Queue.test.ts +227 -0
  107. package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +159 -0
  108. package/Tests/Server/Services/AIAgentTaskPullRequestOutcomeStats.test.ts +154 -0
  109. package/Tests/Server/Services/AIInsightService.test.ts +324 -0
  110. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +401 -0
  111. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +161 -0
  112. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +95 -5
  113. package/Tests/Server/Services/AIServiceProjectAccess.test.ts +259 -0
  114. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +249 -0
  115. package/Tests/Server/Services/FixPerformanceTaskTrigger.test.ts +274 -0
  116. package/Tests/Server/Services/GlobalConfigService.test.ts +80 -0
  117. package/Tests/Server/Services/IncidentInternalNoteAnnouncement.test.ts +1 -1
  118. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +313 -0
  119. package/Tests/Server/Services/LlmProviderProjectOwned.test.ts +132 -0
  120. package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +405 -0
  121. package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +322 -0
  122. package/Tests/Server/Services/TraceServiceLatencyProfile.test.ts +278 -0
  123. package/Tests/Server/Types/Workflow/Components/AIGenerateText.test.ts +722 -0
  124. package/Tests/Server/Utils/AI/{SentinelAlertGating.test.ts → AIAlertGating.test.ts} +19 -19
  125. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +362 -0
  126. package/Tests/Server/Utils/AI/{SentinelInvestigationQueue.test.ts → AIInvestigationQueue.test.ts} +19 -19
  127. package/Tests/Server/Utils/AI/CodeAgentWorkspaceGuard.test.ts +138 -0
  128. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +335 -0
  129. package/Tests/Server/Utils/AI/CodeFixRunQueue.test.ts +134 -0
  130. package/Tests/Server/Utils/AI/EvalCorpus.test.ts +209 -0
  131. package/Tests/Server/Utils/AI/EvalScores.test.ts +343 -0
  132. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +218 -0
  133. package/Tests/Server/Utils/AI/Insights/ErrorLogSpikeDetector.test.ts +437 -0
  134. package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +287 -0
  135. package/Tests/Server/Utils/AI/Insights/InsightDetectorsIndex.test.ts +34 -0
  136. package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +572 -0
  137. package/Tests/Server/Utils/AI/Insights/InsightNeverThrowsHardening.test.ts +344 -0
  138. package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +720 -0
  139. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +467 -0
  140. package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +370 -0
  141. package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +210 -0
  142. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +221 -0
  143. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +328 -0
  144. package/Tests/Server/Utils/AI/Insights/MetricBaselineDrift.test.ts +182 -0
  145. package/Tests/Server/Utils/AI/Insights/MetricDriftDetector.test.ts +280 -0
  146. package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +259 -0
  147. package/Tests/Server/Utils/AI/Insights/TraceLatencyRegressionDetector.test.ts +770 -0
  148. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +343 -0
  149. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +307 -0
  150. package/Tests/Server/Utils/AI/OpenPullRequestCap.test.ts +170 -0
  151. package/Tests/Server/Utils/AI/SpanTreeAnalyzer.test.ts +559 -0
  152. package/Tests/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.test.ts +158 -0
  153. package/Tests/Server/Utils/GitHubCheckRunsConclusion.test.ts +100 -0
  154. package/Tests/Server/Utils/GitHubPullRequestStateMapping.test.ts +50 -0
  155. package/Tests/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.test.ts +266 -0
  156. package/Tests/Server/Utils/ServiceRepoLinkSuggester.test.ts +167 -0
  157. package/Tests/Server/Utils/StackTraceRepoResolver.test.ts +527 -0
  158. package/Tests/Types/AI/AIChatPermissionMode.test.ts +112 -0
  159. package/Tests/Types/AI/CodeFixTaskType.test.ts +152 -0
  160. package/Tests/Types/AI/FixPullRequestCiStatus.test.ts +181 -0
  161. package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +110 -0
  162. package/Tests/Types/Monitor/SqlDatabaseType.test.ts +55 -0
  163. package/Tests/Types/Workflow/AIGenerateTextMetadata.test.ts +180 -0
  164. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +168 -0
  165. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +523 -0
  166. package/Types/AI/AIChatTypes.ts +8 -0
  167. package/Types/AI/AIInsightEvidence.ts +77 -0
  168. package/Types/AI/AIInsightHumanVerdict.ts +15 -0
  169. package/Types/AI/AIInsightSeverity.ts +13 -0
  170. package/Types/AI/AIInsightStatus.ts +38 -0
  171. package/Types/AI/AIInsightType.ts +41 -0
  172. package/Types/AI/AIRunAutoGrade.ts +18 -0
  173. package/Types/AI/AIRunEventType.ts +5 -0
  174. package/Types/AI/AIRunHumanVerdict.ts +17 -0
  175. package/Types/AI/AIRunType.ts +6 -0
  176. package/Types/AI/CodeFixTaskContext.ts +88 -0
  177. package/Types/AI/CodeFixTaskType.ts +132 -0
  178. package/Types/AI/FixPullRequestCiStatus.ts +132 -0
  179. package/Types/BaseDatabase/AggregationIntervalUtil.ts +67 -0
  180. package/Types/Incident/IncidentMetricType.ts +7 -0
  181. package/Types/Monitor/CriteriaFilter.ts +8 -0
  182. package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
  183. package/Types/Monitor/MonitorStep.ts +38 -0
  184. package/Types/Monitor/MonitorStepSqlMonitor.ts +141 -0
  185. package/Types/Monitor/MonitorType.ts +17 -0
  186. package/Types/Monitor/SqlDatabaseType.ts +49 -0
  187. package/Types/Monitor/SqlMonitor/SqlMonitorResponse.ts +28 -0
  188. package/Types/Permission.ts +11 -95
  189. package/Types/Probe/ProbeMonitorResponse.ts +2 -0
  190. package/Types/Runbook/RunbookStep.ts +26 -2
  191. package/Types/Runbook/RunbookStepType.ts +1 -0
  192. package/Types/Workflow/Component.ts +13 -0
  193. package/Types/Workflow/ComponentID.ts +1 -0
  194. package/Types/Workflow/Components/AI.ts +148 -0
  195. package/Types/Workflow/Components.ts +8 -0
  196. package/UI/Components/AI/GenerateFromAIModal.tsx +1 -1
  197. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +11 -0
  198. package/UI/Components/MoreMenu/MoreMenu.tsx +1 -1
  199. package/UI/Components/Table/Table.tsx +38 -2
  200. package/UI/Utils/TableColumnsToCsv.ts +385 -0
  201. package/Utils/Monitor/MonitorMetricType.ts +1 -0
  202. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +59 -45
  203. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/AIInsight.js +795 -0
  205. package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -0
  206. package/build/dist/Models/DatabaseModels/AIRun.js +274 -0
  207. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/CodeRepository.js +43 -0
  209. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/GlobalConfig.js +110 -0
  211. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/Index.js +4 -8
  213. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/InstanceHealthLog.js +304 -0
  215. package/build/dist/Models/DatabaseModels/InstanceHealthLog.js.map +1 -0
  216. package/build/dist/Models/DatabaseModels/LlmLog.js +35 -0
  217. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  218. package/build/dist/Models/DatabaseModels/Project.js +127 -6
  219. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  220. package/build/dist/Models/DatabaseModels/Runbook.js +1 -1
  221. package/build/dist/Models/DatabaseModels/Runbook.js.map +1 -1
  222. package/build/dist/Server/API/AIAgentDataAPI.js +568 -85
  223. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  224. package/build/dist/Server/API/AIAgentTaskAPI.js +100 -44
  225. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
  226. package/build/dist/Server/API/AIAgentTaskLogAPI.js +49 -25
  227. package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
  228. package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js +27 -0
  229. package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js.map +1 -1
  230. package/build/dist/Server/API/AIInsightAPI.js +140 -0
  231. package/build/dist/Server/API/AIInsightAPI.js.map +1 -0
  232. package/build/dist/Server/API/AIInvestigationAPI.js +257 -1
  233. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  234. package/build/dist/Server/API/CodeFixRunAPI.js +181 -0
  235. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -0
  236. package/build/dist/Server/API/GitHubAPI.js +164 -2
  237. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  238. package/build/dist/Server/API/TelemetryExceptionAPI.js +148 -43
  239. package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
  240. package/build/dist/Server/EnvironmentConfig.js +1 -1
  241. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.js +23 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.js.map +1 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.js +32 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.js.map +1 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.js +16 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.js.map +1 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.js +16 -0
  249. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.js.map +1 -0
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.js +24 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.js +16 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.js +24 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.js.map +1 -0
  256. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.js +24 -0
  257. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.js.map +1 -0
  258. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.js +24 -0
  259. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.js.map +1 -0
  260. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.js +18 -0
  261. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.js.map +1 -0
  262. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.js +18 -0
  263. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.js.map +1 -0
  264. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.js +32 -0
  265. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.js.map +1 -0
  266. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.js +18 -0
  267. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.js.map +1 -0
  268. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.js +125 -0
  269. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.js.map +1 -0
  270. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.js +62 -0
  271. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.js.map +1 -0
  272. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +30 -0
  273. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  274. package/build/dist/Server/Infrastructure/Queue.js +73 -3
  275. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  276. package/build/dist/Server/Infrastructure/Semaphore.js +44 -1
  277. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  278. package/build/dist/Server/Services/AIAgentService.js +29 -0
  279. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  280. package/build/dist/Server/Services/AIAgentTaskPullRequestService.js +78 -0
  281. package/build/dist/Server/Services/AIAgentTaskPullRequestService.js.map +1 -1
  282. package/build/dist/Server/Services/AIInsightService.js +164 -0
  283. package/build/dist/Server/Services/AIInsightService.js.map +1 -0
  284. package/build/dist/Server/Services/AIRunEventService.js +49 -0
  285. package/build/dist/Server/Services/AIRunEventService.js.map +1 -1
  286. package/build/dist/Server/Services/AIRunService.js +221 -0
  287. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  288. package/build/dist/Server/Services/AIService.js +198 -11
  289. package/build/dist/Server/Services/AIService.js.map +1 -1
  290. package/build/dist/Server/Services/AlertService.js +4 -4
  291. package/build/dist/Server/Services/AlertService.js.map +1 -1
  292. package/build/dist/Server/Services/CodeRepositoryService.js +180 -0
  293. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
  294. package/build/dist/Server/Services/GlobalConfigService.js +84 -0
  295. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  296. package/build/dist/Server/Services/IncidentService.js +149 -37
  297. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  298. package/build/dist/Server/Services/IncidentStateTimelineService.js +24 -4
  299. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  300. package/build/dist/Server/Services/Index.js +4 -4
  301. package/build/dist/Server/Services/Index.js.map +1 -1
  302. package/build/dist/Server/Services/{AIAgentTaskLogService.js → InstanceHealthLogService.js} +2 -2
  303. package/build/dist/Server/Services/InstanceHealthLogService.js.map +1 -0
  304. package/build/dist/Server/Services/LlmLogService.js +23 -0
  305. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  306. package/build/dist/Server/Services/LlmProviderService.js +96 -0
  307. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  308. package/build/dist/Server/Services/MetricBaselineService.js +65 -0
  309. package/build/dist/Server/Services/MetricBaselineService.js.map +1 -1
  310. package/build/dist/Server/Services/MonitorService.js +9 -1
  311. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  312. package/build/dist/Server/Services/TelemetryExceptionService.js +243 -82
  313. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  314. package/build/dist/Server/Services/TraceAggregationService.js +124 -0
  315. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  316. package/build/dist/Server/Types/Workflow/ComponentCode.js.map +1 -1
  317. package/build/dist/Server/Types/Workflow/Components/AI/GenerateText.js +240 -0
  318. package/build/dist/Server/Types/Workflow/Components/AI/GenerateText.js.map +1 -0
  319. package/build/dist/Server/Types/Workflow/Components/Index.js +2 -0
  320. package/build/dist/Server/Types/Workflow/Components/Index.js.map +1 -1
  321. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +48 -0
  322. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -0
  323. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +174 -0
  324. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -0
  325. package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js +126 -0
  326. package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js.map +1 -0
  327. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +131 -0
  328. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -0
  329. package/build/dist/Server/Utils/AI/CodeFix/OpenPullRequestCap.js +99 -0
  330. package/build/dist/Server/Utils/AI/CodeFix/OpenPullRequestCap.js.map +1 -0
  331. package/build/dist/Server/Utils/AI/Eval/EvalCorpus.js +245 -0
  332. package/build/dist/Server/Utils/AI/Eval/EvalCorpus.js.map +1 -0
  333. package/build/dist/Server/Utils/AI/Eval/EvalScores.js +83 -0
  334. package/build/dist/Server/Utils/AI/Eval/EvalScores.js.map +1 -0
  335. package/build/dist/Server/Utils/AI/Eval/ReplayInvestigation.js +12 -0
  336. package/build/dist/Server/Utils/AI/Eval/ReplayInvestigation.js.map +1 -0
  337. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js +439 -0
  338. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js.map +1 -0
  339. package/build/dist/Server/Utils/AI/{Sentinel/SentinelInvestigationEngine.js → SRE/AIInvestigationEngine.js} +47 -31
  340. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -0
  341. package/build/dist/Server/Utils/AI/{Sentinel/SentinelMemory.js → SRE/AIMemory.js} +5 -5
  342. package/build/dist/Server/Utils/AI/SRE/AIMemory.js.map +1 -0
  343. package/build/dist/Server/Utils/AI/{Sentinel → SRE}/AlertInvestigationRunner.js +42 -19
  344. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -0
  345. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +226 -0
  346. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -0
  347. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +100 -0
  348. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -0
  349. package/build/dist/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.js +174 -0
  350. package/build/dist/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.js.map +1 -0
  351. package/build/dist/Server/Utils/AI/{Sentinel → SRE}/IncidentInvestigationRunner.js +60 -22
  352. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -0
  353. package/build/dist/Server/Utils/AI/{Sentinel → SRE}/IncidentPostmortemRunner.js +9 -9
  354. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -0
  355. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.js +268 -0
  356. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.js.map +1 -0
  357. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +226 -0
  358. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -0
  359. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/Index.js +26 -0
  360. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/Index.js.map +1 -0
  361. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.js +159 -0
  362. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.js.map +1 -0
  363. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +177 -0
  364. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -0
  365. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.js +384 -0
  366. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.js.map +1 -0
  367. package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js +180 -0
  368. package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -0
  369. package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js +269 -0
  370. package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js.map +1 -0
  371. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +231 -0
  372. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -0
  373. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +206 -0
  374. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -0
  375. package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js +121 -0
  376. package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js.map +1 -0
  377. package/build/dist/Server/Utils/AI/SRE/Insights/Types.js +2 -0
  378. package/build/dist/Server/Utils/AI/SRE/Insights/Types.js.map +1 -0
  379. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +148 -0
  380. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -0
  381. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +231 -0
  382. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -0
  383. package/build/dist/Server/Utils/AI/{Sentinel → SRE}/InvestigationQueue.js +102 -23
  384. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -0
  385. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +167 -0
  386. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -0
  387. package/build/dist/Server/Utils/AI/Toolbox/{SentinelActionTools.js → AIActionTools.js} +18 -2
  388. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -0
  389. package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -2
  390. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  391. package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js +301 -0
  392. package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js.map +1 -0
  393. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +240 -2
  394. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  395. package/build/dist/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.js +127 -0
  396. package/build/dist/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.js.map +1 -0
  397. package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js +336 -0
  398. package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js.map +1 -0
  399. package/build/dist/Server/Utils/Execute.js.map +1 -1
  400. package/build/dist/Server/Utils/LLM/LLMService.js +125 -25
  401. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  402. package/build/dist/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.js +120 -0
  403. package/build/dist/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.js.map +1 -0
  404. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -0
  405. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  406. package/build/dist/Types/AI/AIInsightEvidence.js +2 -0
  407. package/build/dist/Types/AI/AIInsightEvidence.js.map +1 -0
  408. package/build/dist/Types/AI/AIInsightHumanVerdict.js +16 -0
  409. package/build/dist/Types/AI/AIInsightHumanVerdict.js.map +1 -0
  410. package/build/dist/Types/AI/AIInsightSeverity.js +14 -0
  411. package/build/dist/Types/AI/AIInsightSeverity.js.map +1 -0
  412. package/build/dist/Types/AI/AIInsightStatus.js +36 -0
  413. package/build/dist/Types/AI/AIInsightStatus.js.map +1 -0
  414. package/build/dist/Types/AI/AIInsightType.js +42 -0
  415. package/build/dist/Types/AI/AIInsightType.js.map +1 -0
  416. package/build/dist/Types/AI/AIRunAutoGrade.js +19 -0
  417. package/build/dist/Types/AI/AIRunAutoGrade.js.map +1 -0
  418. package/build/dist/Types/AI/AIRunEventType.js +5 -0
  419. package/build/dist/Types/AI/AIRunEventType.js.map +1 -1
  420. package/build/dist/Types/AI/AIRunHumanVerdict.js +18 -0
  421. package/build/dist/Types/AI/AIRunHumanVerdict.js.map +1 -0
  422. package/build/dist/Types/AI/AIRunType.js +6 -0
  423. package/build/dist/Types/AI/AIRunType.js.map +1 -1
  424. package/build/dist/Types/AI/CodeFixTaskContext.js +29 -0
  425. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -0
  426. package/build/dist/Types/AI/CodeFixTaskType.js +122 -0
  427. package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -0
  428. package/build/dist/Types/AI/FixPullRequestCiStatus.js +102 -0
  429. package/build/dist/Types/AI/FixPullRequestCiStatus.js.map +1 -0
  430. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +55 -0
  431. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
  432. package/build/dist/Types/Incident/IncidentMetricType.js +7 -0
  433. package/build/dist/Types/Incident/IncidentMetricType.js.map +1 -1
  434. package/build/dist/Types/Monitor/CriteriaFilter.js +7 -0
  435. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  436. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
  437. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  438. package/build/dist/Types/Monitor/MonitorStep.js +28 -0
  439. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  440. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +93 -0
  441. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -0
  442. package/build/dist/Types/Monitor/MonitorType.js +15 -0
  443. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  444. package/build/dist/Types/Monitor/SqlDatabaseType.js +47 -0
  445. package/build/dist/Types/Monitor/SqlDatabaseType.js.map +1 -0
  446. package/build/dist/Types/Monitor/SqlMonitor/SqlMonitorResponse.js +2 -0
  447. package/build/dist/Types/Monitor/SqlMonitor/SqlMonitorResponse.js.map +1 -0
  448. package/build/dist/Types/Permission.js +10 -84
  449. package/build/dist/Types/Permission.js.map +1 -1
  450. package/build/dist/Types/Runbook/RunbookStepType.js +1 -0
  451. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  452. package/build/dist/Types/Workflow/ComponentID.js +1 -0
  453. package/build/dist/Types/Workflow/ComponentID.js.map +1 -1
  454. package/build/dist/Types/Workflow/Components/AI.js +135 -0
  455. package/build/dist/Types/Workflow/Components/AI.js.map +1 -0
  456. package/build/dist/Types/Workflow/Components.js +7 -0
  457. package/build/dist/Types/Workflow/Components.js.map +1 -1
  458. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -1
  459. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  460. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +9 -0
  461. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  462. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +1 -1
  463. package/build/dist/UI/Components/Table/Table.js +28 -2
  464. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  465. package/build/dist/UI/Utils/TableColumnsToCsv.js +291 -0
  466. package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -0
  467. package/build/dist/Utils/Monitor/MonitorMetricType.js +1 -0
  468. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  469. package/package.json +1 -1
  470. package/Models/DatabaseModels/AIAgentTask.ts +0 -660
  471. package/Models/DatabaseModels/AIAgentTaskLog.ts +0 -426
  472. package/Models/DatabaseModels/AIAgentTaskTelemetryException.ts +0 -399
  473. package/Models/DatabaseModels/ServiceCodeRepository.ts +0 -647
  474. package/Server/Services/AIAgentTaskService.ts +0 -240
  475. package/Server/Services/AIAgentTaskTelemetryExceptionService.ts +0 -39
  476. package/Server/Services/ServiceCodeRepositoryService.ts +0 -55
  477. package/Tests/Server/Services/AIAgentTaskServiceClaim.test.ts +0 -146
  478. package/Types/AI/AIAgentTaskMetadata.ts +0 -25
  479. package/Types/AI/AIAgentTaskType.ts +0 -40
  480. package/build/dist/Models/DatabaseModels/AIAgentTask.js +0 -691
  481. package/build/dist/Models/DatabaseModels/AIAgentTask.js.map +0 -1
  482. package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js +0 -447
  483. package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js.map +0 -1
  484. package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js +0 -415
  485. package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js.map +0 -1
  486. package/build/dist/Models/DatabaseModels/ServiceCodeRepository.js +0 -665
  487. package/build/dist/Models/DatabaseModels/ServiceCodeRepository.js.map +0 -1
  488. package/build/dist/Server/Services/AIAgentTaskLogService.js.map +0 -1
  489. package/build/dist/Server/Services/AIAgentTaskService.js +0 -217
  490. package/build/dist/Server/Services/AIAgentTaskService.js.map +0 -1
  491. package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js +0 -36
  492. package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js.map +0 -1
  493. package/build/dist/Server/Services/ServiceCodeRepositoryService.js +0 -54
  494. package/build/dist/Server/Services/ServiceCodeRepositoryService.js.map +0 -1
  495. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +0 -1
  496. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +0 -1
  497. package/build/dist/Server/Utils/AI/Sentinel/IncidentPostmortemRunner.js.map +0 -1
  498. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +0 -1
  499. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +0 -1
  500. package/build/dist/Server/Utils/AI/Sentinel/SentinelMemory.js.map +0 -1
  501. package/build/dist/Server/Utils/AI/Toolbox/SentinelActionTools.js.map +0 -1
  502. package/build/dist/Types/AI/AIAgentTaskMetadata.js +0 -6
  503. package/build/dist/Types/AI/AIAgentTaskMetadata.js.map +0 -1
  504. package/build/dist/Types/AI/AIAgentTaskType.js +0 -29
  505. package/build/dist/Types/AI/AIAgentTaskType.js.map +0 -1
@@ -0,0 +1,283 @@
1
+ import ObjectID from "../../../../../Types/ObjectID";
2
+ import OneUptimeDate from "../../../../../Types/Date";
3
+ import ColumnLength from "../../../../../Types/Database/ColumnLength";
4
+ import SortOrder from "../../../../../Types/BaseDatabase/SortOrder";
5
+ import AIInsight from "../../../../../Models/DatabaseModels/AIInsight";
6
+ import AIInsightStatus, {
7
+ AIInsightStatusHelper,
8
+ } from "../../../../../Types/AI/AIInsightStatus";
9
+ import AIInsightService from "../../../../Services/AIInsightService";
10
+ import { InsightCandidate } from "./Types";
11
+ import logger from "../../../Logger";
12
+ import CaptureSpan from "../../../Telemetry/CaptureSpan";
13
+
14
+ /*
15
+ * AI Insights — the dedupe/upsert store between detectors and the
16
+ * AIInsight table. Detectors re-emit the same finding on every scan
17
+ * tick while the underlying signal persists; the store's job is to keep the
18
+ * inbox quiet: one row per live finding (refreshed in place), a cooldown on
19
+ * findings a human already dismissed, and a hard cap on how many NEW rows a
20
+ * single scan may create.
21
+ */
22
+
23
+ /*
24
+ * G4/G11 volume guardrail: a single scan tick may create at most this many
25
+ * NEW insights per project. A telemetry storm (deploy gone wrong, detector
26
+ * mis-tuning) would otherwise flood the inbox — and every new insight fans
27
+ * out into budgeted triage/fix work. Recurring findings still refresh their
28
+ * existing rows beyond the cap; drops are logged, never silent.
29
+ */
30
+ export const MAX_NEW_INSIGHTS_PER_PROJECT_PER_SCAN: number = 10;
31
+
32
+ /*
33
+ * G11 noise posture: a human dismissal is the strongest precision signal we
34
+ * have, so a finding with the same fingerprint stays suppressed for this
35
+ * many days after the dismissal instead of reappearing on the next tick.
36
+ * After the cooldown (or after a Resolved insight's signal returns) a fresh
37
+ * insight is warranted — a resolved issue that reappears is a regression.
38
+ */
39
+ export const DISMISSED_COOLDOWN_DAYS: number = 7;
40
+
41
+ /*
42
+ * Column-safety clamps: DatabaseService validates string columns against the
43
+ * model's declared lengths and THROWS on overflow, and detectors embed raw
44
+ * telemetry strings (a span name can be an entire SQL statement, exception
45
+ * types and service names are unbounded). Clamping here — the single choke
46
+ * point where candidates become rows — protects every current and future
47
+ * detector. The fingerprint clamp is applied to the dedupe LOOKUP as well as
48
+ * the insert, so a clamped fingerprint keeps refreshing the same row instead
49
+ * of failing (or duplicating) on every tick. Values mirror the
50
+ * AIInsight column definitions (LongText/ShortText).
51
+ */
52
+ export const INSIGHT_FINGERPRINT_MAX_LENGTH: number = ColumnLength.LongText;
53
+ export const INSIGHT_TITLE_MAX_LENGTH: number = ColumnLength.LongText;
54
+ export const INSIGHT_SERVICE_NAME_MAX_LENGTH: number = ColumnLength.LongText;
55
+ export const INSIGHT_METRIC_NAME_MAX_LENGTH: number = ColumnLength.LongText;
56
+ export const INSIGHT_TRACE_ID_MAX_LENGTH: number = ColumnLength.ShortText;
57
+
58
+ export interface UpsertCandidatesResult {
59
+ // Newly created insights (status Detected) — the scanner routes these.
60
+ created: Array<AIInsight>;
61
+ // Existing non-terminal insights refreshed in place.
62
+ refreshed: number;
63
+ // Candidates suppressed by the dismissed-fingerprint cooldown.
64
+ suppressed: number;
65
+ // Candidates dropped by MAX_NEW_INSIGHTS_PER_PROJECT_PER_SCAN.
66
+ droppedByCap: number;
67
+ }
68
+
69
+ export default class InsightStore {
70
+ /*
71
+ * Upsert one scan tick's candidates for one project. For each candidate,
72
+ * the most recent insight with the same (projectId, fingerprint) decides
73
+ * the outcome:
74
+ * - none → CREATE (subject to the per-scan cap)
75
+ * - non-terminal → REFRESH (never touches status)
76
+ * - Dismissed within the cooldown → suppress
77
+ * - Dismissed past the cooldown,
78
+ * or Resolved → CREATE (regression / recurrence)
79
+ * All access is root-props: the scanner is a system actor with explicit
80
+ * projectId scoping, not a per-user ACL consumer.
81
+ */
82
+ @CaptureSpan()
83
+ public static async upsertCandidates(data: {
84
+ projectId: ObjectID;
85
+ candidates: Array<InsightCandidate>;
86
+ now: Date;
87
+ }): Promise<UpsertCandidatesResult> {
88
+ const result: UpsertCandidatesResult = {
89
+ created: [],
90
+ refreshed: 0,
91
+ suppressed: 0,
92
+ droppedByCap: 0,
93
+ };
94
+
95
+ // No silent caps: dropped fingerprints are logged after the loop.
96
+ const droppedFingerprints: Array<string> = [];
97
+
98
+ for (const candidate of data.candidates) {
99
+ /*
100
+ * Per-candidate isolation: one failing candidate (transient DB error,
101
+ * unexpected data) must not abort the batch — insights created earlier
102
+ * in this tick are returned for routing either way, and the remaining
103
+ * candidates still get their chance. Without this, a mid-batch failure
104
+ * would strand already-created rows in Detected forever (refreshes
105
+ * never touch status, so they would never be routed).
106
+ */
107
+ try {
108
+ /*
109
+ * The clamped fingerprint is the row's identity everywhere — lookup
110
+ * and insert — so dedupe survives the clamp (see the constants).
111
+ */
112
+ const fingerprint: string = this.clampToColumn(
113
+ candidate.fingerprint,
114
+ INSIGHT_FINGERPRINT_MAX_LENGTH,
115
+ );
116
+
117
+ /*
118
+ * Most recent row wins: (projectId, fingerprint) is deliberately NOT
119
+ * unique — terminal rows accumulate as history — so sort by createdAt
120
+ * to judge against the latest lifecycle state of this finding.
121
+ */
122
+ const existing: AIInsight | null = await AIInsightService.findOneBy({
123
+ query: {
124
+ projectId: data.projectId,
125
+ fingerprint: fingerprint,
126
+ },
127
+ select: {
128
+ _id: true,
129
+ status: true,
130
+ occurrenceCount: true,
131
+ humanVerdictAt: true,
132
+ },
133
+ sort: { createdAt: SortOrder.Descending },
134
+ props: { isRoot: true },
135
+ });
136
+
137
+ if (
138
+ existing &&
139
+ existing.status &&
140
+ !AIInsightStatusHelper.isTerminalStatus(existing.status)
141
+ ) {
142
+ /*
143
+ * REFRESH: the finding is still live and already has a row. The
144
+ * evidence/severity are replaced with this tick's numbers (the
145
+ * newest picture of the signal), but status is NEVER touched here —
146
+ * routing (ActionRequired/FixOpened) happened when the row was
147
+ * created and humans/fix flows own it from there.
148
+ */
149
+ await AIInsightService.updateOneById({
150
+ id: existing.id!,
151
+ data: {
152
+ lastSeenAt: data.now,
153
+ occurrenceCount: (existing.occurrenceCount || 1) + 1,
154
+ severity: candidate.severity,
155
+ detailMarkdown: candidate.detailMarkdown,
156
+ evidence: candidate.evidence,
157
+ },
158
+ props: { isRoot: true },
159
+ });
160
+
161
+ result.refreshed++;
162
+ continue;
163
+ }
164
+
165
+ if (existing && existing.status === AIInsightStatus.Dismissed) {
166
+ /*
167
+ * Cooldown is measured from the human's dismissal, inclusive at the
168
+ * boundary (exactly DISMISSED_COOLDOWN_DAYS old still suppresses).
169
+ * A Dismissed row without a verdict timestamp cannot prove the
170
+ * cooldown elapsed, so it suppresses too — when in doubt, stay
171
+ * quiet (G11 noise posture).
172
+ */
173
+ const cooldownMs: number = OneUptimeDate.getMillisecondsInDays(
174
+ DISMISSED_COOLDOWN_DAYS,
175
+ );
176
+
177
+ const withinCooldown: boolean = existing.humanVerdictAt
178
+ ? data.now.getTime() -
179
+ OneUptimeDate.fromString(existing.humanVerdictAt).getTime() <=
180
+ cooldownMs
181
+ : true;
182
+
183
+ if (withinCooldown) {
184
+ logger.debug(
185
+ `AI Insights: suppressing candidate ${fingerprint} for project ${data.projectId.toString()} — dismissed by a human within the last ${DISMISSED_COOLDOWN_DAYS} days.`,
186
+ );
187
+
188
+ result.suppressed++;
189
+ continue;
190
+ }
191
+ }
192
+
193
+ /*
194
+ * CREATE: no live row for this fingerprint (never seen, Resolved, or
195
+ * Dismissed long enough ago). Subject to the per-scan cap.
196
+ */
197
+ if (result.created.length >= MAX_NEW_INSIGHTS_PER_PROJECT_PER_SCAN) {
198
+ droppedFingerprints.push(fingerprint);
199
+ result.droppedByCap++;
200
+ continue;
201
+ }
202
+
203
+ const insight: AIInsight = new AIInsight();
204
+ insight.projectId = data.projectId;
205
+ insight.insightType = candidate.insightType;
206
+ // Defensive initial state — the scanner routes it in the same tick.
207
+ insight.status = AIInsightStatus.Detected;
208
+ insight.severity = candidate.severity;
209
+ insight.fingerprint = fingerprint;
210
+ insight.title = this.clampToColumn(
211
+ candidate.title,
212
+ INSIGHT_TITLE_MAX_LENGTH,
213
+ );
214
+ insight.detailMarkdown = candidate.detailMarkdown;
215
+ insight.evidence = candidate.evidence;
216
+ insight.firstSeenAt = data.now;
217
+ insight.lastSeenAt = data.now;
218
+ insight.occurrenceCount = 1;
219
+
220
+ if (candidate.serviceName) {
221
+ insight.serviceName = this.clampToColumn(
222
+ candidate.serviceName,
223
+ INSIGHT_SERVICE_NAME_MAX_LENGTH,
224
+ );
225
+ }
226
+ if (candidate.telemetryServiceId) {
227
+ insight.telemetryServiceId = candidate.telemetryServiceId;
228
+ }
229
+ if (candidate.telemetryExceptionId) {
230
+ insight.telemetryExceptionId = candidate.telemetryExceptionId;
231
+ }
232
+ if (candidate.traceId) {
233
+ insight.traceId = this.clampToColumn(
234
+ candidate.traceId,
235
+ INSIGHT_TRACE_ID_MAX_LENGTH,
236
+ );
237
+ }
238
+ if (candidate.metricName) {
239
+ insight.metricName = this.clampToColumn(
240
+ candidate.metricName,
241
+ INSIGHT_METRIC_NAME_MAX_LENGTH,
242
+ );
243
+ }
244
+
245
+ const created: AIInsight = await AIInsightService.create({
246
+ data: insight,
247
+ props: { isRoot: true },
248
+ });
249
+
250
+ result.created.push(created);
251
+ } catch (error) {
252
+ logger.error(
253
+ `AI Insights: upsert failed for candidate ${candidate.fingerprint} (project ${data.projectId.toString()}) — continuing with the remaining candidates: ${error}`,
254
+ );
255
+ }
256
+ }
257
+
258
+ if (result.droppedByCap > 0) {
259
+ logger.debug(
260
+ `AI Insights: candidate fingerprints dropped by the per-scan cap for project ${data.projectId.toString()}: ${droppedFingerprints.join(", ")}`,
261
+ );
262
+ logger.info(
263
+ `AI Insights: per-scan new-insight cap (${MAX_NEW_INSIGHTS_PER_PROJECT_PER_SCAN}) reached for project ${data.projectId.toString()} — dropped ${result.droppedByCap} candidate(s) this tick. Recurring findings will re-surface on later ticks if their signal persists.`,
264
+ );
265
+ }
266
+
267
+ return result;
268
+ }
269
+
270
+ /*
271
+ * Hard code-unit slice to the column's declared length — the same measure
272
+ * DatabaseService validates against, so a clamped value can never trip the
273
+ * length check. No cosmetic ellipsis: detectors own presentation; this is
274
+ * purely a data-safety guard, and it must be deterministic so a clamped
275
+ * fingerprint stays stable across ticks.
276
+ */
277
+ private static clampToColumn(value: string, maxLength: number): string {
278
+ if (value.length <= maxLength) {
279
+ return value;
280
+ }
281
+ return value.slice(0, maxLength);
282
+ }
283
+ }
@@ -0,0 +1,242 @@
1
+ import ObjectID from "../../../../../Types/ObjectID";
2
+ import OneUptimeDate from "../../../../../Types/Date";
3
+ import AIInsight from "../../../../../Models/DatabaseModels/AIInsight";
4
+ import AIInsightEvidence from "../../../../../Types/AI/AIInsightEvidence";
5
+ import AIInsightService from "../../../../Services/AIInsightService";
6
+ import { AI_INSIGHT_TRIAGE_FEATURE } from "../../../../Services/AIService";
7
+ import AIInvestigationEngine from "../AIInvestigationEngine";
8
+ import AIInvestigationQueue from "../InvestigationQueue";
9
+ import { ConfidenceSignal } from "../ConfidenceSignal";
10
+ import { ObservabilityAssistantResult } from "../../Chat/ObservabilityAssistant";
11
+ import logger from "../../../Logger";
12
+ import CaptureSpan from "../../../Telemetry/CaptureSpan";
13
+
14
+ /*
15
+ * AI SRE — per-insight preventive triage.
16
+ *
17
+ * A deterministic detector filed a AIInsight; this runner executes the
18
+ * budgeted, read-only Investigation AIRun that triages it: most likely root
19
+ * cause, estimated blast radius, ONE recommended next action — every claim
20
+ * cited. Structurally a sibling of IncidentInvestigationRunner: the queue
21
+ * claims the run and dispatches here; the shared engine owns the run
22
+ * lifecycle, the agent loop and the confidence signal.
23
+ *
24
+ * The difference is the OUTPUT SINK. Insights never page and never open
25
+ * incidents (the roadmap's Preventive-lane rule), so postAnalysis writes the
26
+ * summary onto the insight row and NOTHING else — the quiet inbox.
27
+ */
28
+
29
+ /*
30
+ * Cap on the rendered evidence JSON embedded in the triage prompt. Latency
31
+ * evidence carries span-tree findings that can be large; the numbers matter,
32
+ * an exhaustive span listing does not.
33
+ */
34
+ const MAX_RENDERED_EVIDENCE_CHARS: number = 4000;
35
+
36
+ /*
37
+ * The preventive-triage framing, prepended to the subject description. The
38
+ * engine's persona is written for a just-declared incident/alert, so the
39
+ * request context must recast the situation before the insight is described
40
+ * (the engine embeds contextSummary into the investigation question — the
41
+ * same mechanism the incident runner uses to convey its subject).
42
+ */
43
+ const PREVENTIVE_TRIAGE_FRAMING: string = `IMPORTANT — this is PREVENTIVE TRIAGE, not an incident investigation: NO incident or alert exists and nobody has been paged. A deterministic statistical sensor (no AI involved) watched this project's telemetry and filed the finding described below, with the evidence it computed. Your job:
44
+ - Establish the most likely root cause of the finding.
45
+ - Estimate the blast radius: which services/users/operations are affected, and how badly.
46
+ - Recommend exactly ONE next action (the single most useful thing an engineer should do first).
47
+ Cite the evidence for every factual claim. If the telemetry cannot support a conclusion, say so plainly. Do not refer to "the incident" — there is none.`;
48
+
49
+ export default class InsightTriageRunner {
50
+ /*
51
+ * Execute a claimed triage run: load the insight, build its description
52
+ * and hand it to the shared engine. Called by AIInvestigationQueue
53
+ * after a successful claim. Never throws — failures are handed to the
54
+ * queue's retry policy so a claimed run is always finalized or requeued.
55
+ */
56
+ @CaptureSpan()
57
+ public static async executeTriage(data: {
58
+ aiRunId: ObjectID;
59
+ projectId: ObjectID;
60
+ sentinelInsightId: ObjectID;
61
+ attemptCount: number;
62
+ }): Promise<void> {
63
+ const { aiRunId, projectId, sentinelInsightId, attemptCount } = data;
64
+
65
+ let contextSummary: string;
66
+ try {
67
+ const insight: AIInsight | null = await AIInsightService.findOneById({
68
+ id: sentinelInsightId,
69
+ select: {
70
+ _id: true,
71
+ insightType: true,
72
+ severity: true,
73
+ title: true,
74
+ detailMarkdown: true,
75
+ evidence: true,
76
+ serviceName: true,
77
+ traceId: true,
78
+ metricName: true,
79
+ firstSeenAt: true,
80
+ lastSeenAt: true,
81
+ occurrenceCount: true,
82
+ },
83
+ props: { isRoot: true },
84
+ });
85
+
86
+ if (!insight) {
87
+ throw new Error(
88
+ "AI insight not found — it may have been deleted after the triage run was enqueued.",
89
+ );
90
+ }
91
+
92
+ contextSummary = this.buildInsightSummary(insight);
93
+ } catch (error) {
94
+ /*
95
+ * Context assembly failed — the run is claimed, so hand it to the
96
+ * retry policy rather than leaving it Running until the sweeper.
97
+ */
98
+ await AIInvestigationQueue.failOrRequeue({
99
+ aiRunId,
100
+ attemptCount,
101
+ errorMessage: `Failed to build insight context: ${
102
+ error instanceof Error ? error.message : String(error)
103
+ }`,
104
+ isPermanent: false,
105
+ });
106
+ return;
107
+ }
108
+
109
+ await AIInvestigationEngine.executeRun({
110
+ aiRunId,
111
+ projectId,
112
+ attemptCount,
113
+ request: {
114
+ feature: AI_INSIGHT_TRIAGE_FEATURE,
115
+ contextSummary,
116
+ postAnalysis: async (postData: {
117
+ analysisMarkdown: string;
118
+ confidence: ConfidenceSignal;
119
+ result: ObservabilityAssistantResult;
120
+ }): Promise<void> => {
121
+ /*
122
+ * The quiet inbox — deliberately the ONLY write: no feed items,
123
+ * no workspace notification, no owner/on-call ping, no metrics,
124
+ * and no instrumentation-task trigger. Insights never page and
125
+ * never enter the notification pipeline (Preventive-lane rule);
126
+ * the summary waits on the Insights page until a human looks.
127
+ */
128
+ await AIInsightService.updateOneById({
129
+ id: sentinelInsightId,
130
+ data: {
131
+ triageSummaryMarkdown: postData.analysisMarkdown,
132
+ triageCompletedAt: OneUptimeDate.getCurrentDate(),
133
+ },
134
+ props: { isRoot: true },
135
+ });
136
+
137
+ logger.debug(
138
+ `AI insights: triage summary posted for insight ${sentinelInsightId.toString()} (run ${aiRunId.toString()}, confident=${postData.confidence.confident} via ${postData.confidence.source}).`,
139
+ );
140
+ },
141
+ },
142
+ });
143
+ }
144
+
145
+ // Build the compact insight record that seeds the triage.
146
+ private static buildInsightSummary(insight: AIInsight): string {
147
+ const lines: Array<string> = [];
148
+
149
+ lines.push(PREVENTIVE_TRIAGE_FRAMING);
150
+ lines.push("");
151
+ lines.push("# Insight finding");
152
+ lines.push(`Finding type: ${insight.insightType || "N/A"}`);
153
+ lines.push(`Title: ${insight.title || "N/A"}`);
154
+ lines.push(`Severity: ${insight.severity || "N/A"}`);
155
+
156
+ if (insight.serviceName) {
157
+ lines.push(`Attributed service: ${insight.serviceName}`);
158
+ }
159
+ if (insight.metricName) {
160
+ lines.push(`Metric: ${insight.metricName}`);
161
+ }
162
+ if (insight.traceId) {
163
+ lines.push(`Representative trace id: ${insight.traceId}`);
164
+ }
165
+ if (insight.firstSeenAt) {
166
+ lines.push(
167
+ `First seen: ${OneUptimeDate.getDateAsFormattedString(insight.firstSeenAt)}`,
168
+ );
169
+ }
170
+ if (insight.lastSeenAt) {
171
+ lines.push(
172
+ `Last seen: ${OneUptimeDate.getDateAsFormattedString(insight.lastSeenAt)}`,
173
+ );
174
+ }
175
+ if (insight.occurrenceCount) {
176
+ lines.push(`Times detected: ${insight.occurrenceCount}`);
177
+ }
178
+
179
+ if (insight.detailMarkdown) {
180
+ lines.push("");
181
+ lines.push(
182
+ "## Detector's evidence (deterministic, computed at detect time)",
183
+ );
184
+ lines.push(insight.detailMarkdown);
185
+ }
186
+
187
+ const renderedEvidence: string = this.renderEvidence(insight.evidence);
188
+ if (renderedEvidence) {
189
+ lines.push("");
190
+ lines.push("## Raw evidence values");
191
+ lines.push(renderedEvidence);
192
+ }
193
+
194
+ return lines.join("\n");
195
+ }
196
+
197
+ /*
198
+ * Render the stored evidence JSON compactly: one line per populated
199
+ * section, values verbatim (the numbers ARE the evidence), capped so a
200
+ * large span-tree finding cannot flood the prompt.
201
+ */
202
+ private static renderEvidence(
203
+ evidence: AIInsightEvidence | undefined,
204
+ ): string {
205
+ if (!evidence) {
206
+ return "";
207
+ }
208
+
209
+ const lines: Array<string> = [];
210
+
211
+ const sections: Array<keyof AIInsightEvidence> = [
212
+ "exception",
213
+ "logSpike",
214
+ "latency",
215
+ "metricDrift",
216
+ ];
217
+
218
+ for (const section of sections) {
219
+ const value: AIInsightEvidence[keyof AIInsightEvidence] =
220
+ evidence[section];
221
+
222
+ if (!value) {
223
+ continue;
224
+ }
225
+
226
+ let rendered: string;
227
+ try {
228
+ rendered = JSON.stringify(value);
229
+ } catch {
230
+ continue;
231
+ }
232
+
233
+ if (rendered.length > MAX_RENDERED_EVIDENCE_CHARS) {
234
+ rendered = `${rendered.substring(0, MAX_RENDERED_EVIDENCE_CHARS)}… (truncated)`;
235
+ }
236
+
237
+ lines.push(`- ${section}: ${rendered}`);
238
+ }
239
+
240
+ return lines.join("\n");
241
+ }
242
+ }
@@ -0,0 +1,162 @@
1
+ import ObjectID from "../../../../../Types/ObjectID";
2
+ import AIRunType from "../../../../../Types/AI/AIRunType";
3
+ import AIRunStatus from "../../../../../Types/AI/AIRunStatus";
4
+ import AIInsight from "../../../../../Models/DatabaseModels/AIInsight";
5
+ import Project from "../../../../../Models/DatabaseModels/Project";
6
+ import LlmProvider from "../../../../../Models/DatabaseModels/LlmProvider";
7
+ import ProjectService from "../../../../Services/ProjectService";
8
+ import LlmProviderService from "../../../../Services/LlmProviderService";
9
+ import AIRunService from "../../../../Services/AIRunService";
10
+ import AIInsightService from "../../../../Services/AIInsightService";
11
+ import AIInvestigationQueue from "../InvestigationQueue";
12
+ import QueryHelper from "../../../../Types/Database/QueryHelper";
13
+ import logger from "../../../Logger";
14
+ import CaptureSpan from "../../../Telemetry/CaptureSpan";
15
+
16
+ /*
17
+ * Per-insight LLM triage enqueue: a budgeted, read-only Investigation AIRun
18
+ * (triggeredByAiInsightId set) that posts a cited root-cause/blast-
19
+ * radius/suggested-action summary back onto the insight. Quiet-skips when
20
+ * no LLM provider is configured or the budget has no headroom, and dedupes
21
+ * to one non-terminal triage run per insight.
22
+ *
23
+ * The durable queue does the heavy lifting (claim CAS, concurrency cap,
24
+ * daily token budget, retries, TTL expiry, stale sweeping) — this module
25
+ * only owns the insight-specific gates, mirroring the posture of
26
+ * AIInvestigationEngine.isEnabledForProject: enableAi not disabled,
27
+ * the subject's own strict opt-in (Project.enableAiInsights, default
28
+ * FALSE), and a configured LLM provider.
29
+ */
30
+
31
+ export interface InsightTriageResult {
32
+ // Set when a triage run was enqueued for the insight.
33
+ triageAiRunId?: ObjectID | undefined;
34
+ }
35
+
36
+ export default class InsightTriage {
37
+ /*
38
+ * NEVER throws — this runs inside the scanner's per-insight routing and a
39
+ * failed triage enqueue must not fail the scan itself. Every failure is
40
+ * logged and swallowed; an empty result means "no triage enqueued".
41
+ */
42
+ @CaptureSpan()
43
+ public static async enqueueInsightTriage(data: {
44
+ insight: AIInsight;
45
+ }): Promise<InsightTriageResult> {
46
+ const { insight } = data;
47
+
48
+ try {
49
+ if (!insight.id || !insight.projectId) {
50
+ return {};
51
+ }
52
+
53
+ const projectId: ObjectID = insight.projectId;
54
+
55
+ const project: Project | null = await ProjectService.findOneById({
56
+ id: projectId,
57
+ select: {
58
+ enableAi: true,
59
+ enableAiInsights: true,
60
+ },
61
+ props: { isRoot: true },
62
+ });
63
+
64
+ if (!project) {
65
+ logger.debug(
66
+ `AI insights: not enqueueing triage for insight ${insight.id.toString()} — project not found.`,
67
+ );
68
+ return {};
69
+ }
70
+
71
+ if (project.enableAi === false) {
72
+ logger.debug(
73
+ `AI insights: not enqueueing triage for insight ${insight.id.toString()} — AI is disabled for the project.`,
74
+ );
75
+ return {};
76
+ }
77
+
78
+ /*
79
+ * Strict opt-in — the column defaults to false. A triage run only
80
+ * exists because insights exist, so it shares the insights flag; the
81
+ * fix-tasks flag is a separate, stricter opt-in.
82
+ */
83
+ if (project.enableAiInsights !== true) {
84
+ logger.debug(
85
+ `AI insights: not enqueueing triage for insight ${insight.id.toString()} — project has not opted in to AI insights.`,
86
+ );
87
+ return {};
88
+ }
89
+
90
+ const llmProvider: LlmProvider | null =
91
+ await LlmProviderService.getLLMProviderForProject(projectId);
92
+
93
+ if (!llmProvider) {
94
+ logger.debug(
95
+ `AI insights: not enqueueing triage for insight ${insight.id.toString()} — no LLM provider configured.`,
96
+ );
97
+ return {};
98
+ }
99
+
100
+ /*
101
+ * Dedupe: at most one non-terminal triage run per insight — the
102
+ * scanner refreshes recurring insights every tick, and a refresh must
103
+ * not fan out into duplicate triage runs.
104
+ */
105
+ const nonTerminalTriageRunCount: number = (
106
+ await AIRunService.countBy({
107
+ query: {
108
+ runType: AIRunType.Investigation,
109
+ triggeredByAiInsightId: insight.id,
110
+ status: QueryHelper.notIn([
111
+ AIRunStatus.Completed,
112
+ AIRunStatus.Error,
113
+ AIRunStatus.Cancelled,
114
+ AIRunStatus.Stale,
115
+ ]),
116
+ },
117
+ props: { isRoot: true },
118
+ })
119
+ ).toNumber();
120
+
121
+ if (nonTerminalTriageRunCount > 0) {
122
+ logger.debug(
123
+ `AI insights: not enqueueing triage for insight ${insight.id.toString()} — a non-terminal triage run already exists.`,
124
+ );
125
+ return {};
126
+ }
127
+
128
+ /*
129
+ * Record the durable intent. The queue's own budget quiet-skip
130
+ * applies here too — a null result means no run was created (budget
131
+ * exhausted or the create failed) and the insight simply gets no
132
+ * triage this tick.
133
+ */
134
+ const triageAiRunId: ObjectID | null = await AIInvestigationQueue.enqueue(
135
+ {
136
+ projectId,
137
+ subjectAIInsightId: insight.id,
138
+ },
139
+ );
140
+
141
+ if (!triageAiRunId) {
142
+ return {};
143
+ }
144
+
145
+ // Link the insight to its triage run for the dashboard's live panel.
146
+ await AIInsightService.updateOneById({
147
+ id: insight.id,
148
+ data: {
149
+ triageAiRunId,
150
+ },
151
+ props: { isRoot: true },
152
+ });
153
+
154
+ return { triageAiRunId };
155
+ } catch (error) {
156
+ logger.error(
157
+ `AI insights: failed to enqueue triage for insight ${insight.id?.toString()}: ${error}`,
158
+ );
159
+ return {};
160
+ }
161
+ }
162
+ }