@oneuptime/common 11.4.0 → 11.5.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.
Files changed (473) hide show
  1. package/Models/DatabaseModels/AIRun.ts +50 -0
  2. package/Models/DatabaseModels/AlertSeverity.ts +6 -0
  3. package/Models/DatabaseModels/IncidentSeverity.ts +6 -0
  4. package/Models/DatabaseModels/Index.ts +16 -0
  5. package/Models/DatabaseModels/IoTDeviceCredential.ts +471 -0
  6. package/Models/DatabaseModels/LlmLog.ts +56 -0
  7. package/Models/DatabaseModels/LlmProvider.ts +33 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +1385 -0
  9. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +717 -0
  10. package/Models/DatabaseModels/NetworkDeviceLabelRule.ts +514 -0
  11. package/Models/DatabaseModels/NetworkDeviceOwnerRule.ts +596 -0
  12. package/Models/DatabaseModels/NetworkDeviceOwnerTeam.ts +487 -0
  13. package/Models/DatabaseModels/NetworkDeviceOwnerUser.ts +486 -0
  14. package/Models/DatabaseModels/NetworkInterface.ts +563 -0
  15. package/Models/DatabaseModels/Project.ts +145 -0
  16. package/Models/DatabaseModels/TelemetryEntityRelationship.ts +54 -0
  17. package/Server/API/AIAgentTaskAPI.ts +10 -24
  18. package/Server/API/AIInvestigationAPI.ts +131 -63
  19. package/Server/API/AlertAPI.ts +5 -0
  20. package/Server/API/IncidentAPI.ts +10 -0
  21. package/Server/API/IncidentEpisodeAPI.ts +5 -0
  22. package/Server/API/LlmProviderAPI.ts +4 -0
  23. package/Server/API/ScheduledMaintenanceAPI.ts +5 -0
  24. package/Server/API/TelemetryAPI.ts +4 -3
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.ts +19 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.ts +25 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.ts +31 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.ts +19 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.ts +105 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.ts +15 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.ts +192 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.ts +37 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.ts +19 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.ts +25 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.ts +31 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.ts +79 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.ts +49 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +24 -0
  39. package/Server/Services/AIAgentTaskService.ts +62 -0
  40. package/Server/Services/AIRunService.ts +58 -0
  41. package/Server/Services/AIService.ts +101 -0
  42. package/Server/Services/AnalyticsDatabaseService.ts +27 -0
  43. package/Server/Services/IncidentService.ts +14 -41
  44. package/Server/Services/Index.ts +14 -0
  45. package/Server/Services/IoTDeviceCredentialService.ts +351 -0
  46. package/Server/Services/IoTDeviceService.ts +64 -21
  47. package/Server/Services/LlmLogService.ts +26 -0
  48. package/Server/Services/LlmProviderService.ts +3 -0
  49. package/Server/Services/LogAggregationService.ts +29 -11
  50. package/Server/Services/MetricService.ts +603 -13
  51. package/Server/Services/MonitorService.ts +4 -1
  52. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +10 -0
  53. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +204 -0
  54. package/Server/Services/NetworkDeviceLabelRuleService.ts +14 -0
  55. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +222 -0
  56. package/Server/Services/NetworkDeviceOwnerRuleService.ts +14 -0
  57. package/Server/Services/NetworkDeviceOwnerTeamService.ts +10 -0
  58. package/Server/Services/NetworkDeviceOwnerUserService.ts +10 -0
  59. package/Server/Services/NetworkDeviceService.ts +50 -0
  60. package/Server/Services/NetworkInterfaceService.ts +10 -0
  61. package/Server/Services/TelemetryEntityRelationshipService.ts +23 -0
  62. package/Server/Services/TelemetryEntityService.ts +72 -2
  63. package/Server/Utils/AI/Sentinel/AlertInvestigationRunner.ts +244 -12
  64. package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +92 -19
  65. package/Server/Utils/AI/Sentinel/InvestigationQueue.ts +493 -0
  66. package/Server/Utils/AI/Sentinel/README.md +10 -0
  67. package/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.ts +88 -68
  68. package/Server/Utils/AI/Toolbox/Index.ts +2 -1
  69. package/Server/Utils/AI/Toolbox/MetricTools.ts +391 -0
  70. package/Server/Utils/LLM/LLMService.ts +21 -0
  71. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +44 -0
  72. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +170 -2
  73. package/Server/Utils/Monitor/IoTDeviceAbsenceSeries.ts +101 -0
  74. package/Server/Utils/Monitor/MonitorAlert.ts +15 -3
  75. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +1 -1
  76. package/Server/Utils/Monitor/MonitorIncident.ts +19 -3
  77. package/Server/Utils/Monitor/MonitorMetricUtil.ts +195 -2
  78. package/Server/Utils/Monitor/MonitorResource.ts +77 -21
  79. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -1
  80. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +201 -0
  81. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +215 -0
  82. package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +169 -0
  83. package/Tests/Server/Services/AIAgentTaskServiceClaim.test.ts +146 -0
  84. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +173 -0
  85. package/Tests/Server/Services/IncidentInternalNoteAnnouncement.test.ts +97 -0
  86. package/Tests/Server/Services/IoTDeviceService.test.ts +54 -0
  87. package/Tests/Server/Services/LogAggregationService.test.ts +22 -0
  88. package/Tests/Server/Services/MetricServiceAggregate.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/BaselineAnomalyTool.test.ts +253 -0
  90. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +44 -0
  91. package/Tests/Server/Utils/AI/SentinelAlertGating.test.ts +360 -0
  92. package/Tests/Server/Utils/AI/SentinelInvestigationQueue.test.ts +295 -0
  93. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +59 -0
  94. package/Tests/Server/Utils/Monitor/IoTDeviceAbsenceSeries.test.ts +113 -0
  95. package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +198 -0
  96. package/Tests/Types/AI/AIAgentTaskStatus.test.ts +86 -0
  97. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +127 -0
  98. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.test.ts +152 -0
  99. package/Tests/Types/Monitor/MonitorType.test.ts +1 -1
  100. package/Tests/Types/Trace/TraceRecordingRuleDefinition.test.ts +308 -0
  101. package/Tests/UI/Components/Dropdown.test.tsx +17 -0
  102. package/Tests/UI/Components/EntityDropdown.test.tsx +130 -0
  103. package/Tests/UI/Components/Modal.test.tsx +144 -2
  104. package/Tests/UI/Components/TelemetrySearchBar.test.tsx +90 -0
  105. package/Tests/UI/Utils/Theme.test.ts +161 -0
  106. package/Tests/Utils/Monitor/LatencyMatrixUtil.test.ts +111 -0
  107. package/Types/AI/AIRunStatus.ts +9 -0
  108. package/Types/BaseDatabase/AggregateBy.ts +12 -0
  109. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  110. package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +24 -0
  111. package/Types/Dashboard/DashboardTemplates.ts +9 -1
  112. package/Types/LlmLogStatus.ts +1 -0
  113. package/Types/Monitor/CriteriaFilter.ts +9 -0
  114. package/Types/Monitor/HttpPhaseTimings.ts +16 -0
  115. package/Types/Monitor/IotAlertTemplates.ts +22 -3
  116. package/Types/Monitor/LatencyMatrix.ts +27 -0
  117. package/Types/Monitor/MonitorCriteriaInstance.ts +2 -2
  118. package/Types/Monitor/MonitorMetricType.ts +27 -0
  119. package/Types/Monitor/MonitorStep.ts +36 -11
  120. package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +55 -0
  121. package/Types/Monitor/MonitorStepSnmpMonitor.ts +8 -0
  122. package/Types/Monitor/MonitorType.ts +14 -9
  123. package/Types/Monitor/PingMonitor/PingMonitorResponse.ts +20 -0
  124. package/Types/Monitor/SnmpMonitor/LldpNeighbor.ts +12 -0
  125. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +116 -0
  126. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +29 -0
  127. package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +31 -0
  128. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +24 -0
  129. package/Types/Monitor/SnmpMonitor/SnmpTrap.ts +20 -0
  130. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +173 -0
  131. package/Types/Permission.ts +314 -0
  132. package/Types/Probe/ProbeMonitorResponse.ts +22 -0
  133. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -5
  134. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +4 -1
  135. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +6 -3
  136. package/UI/Components/CodeBlock/CodeBlock.tsx +2 -1
  137. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  138. package/UI/Components/Divider/Divider.tsx +1 -1
  139. package/UI/Components/Dropdown/Dropdown.tsx +13 -4
  140. package/UI/Components/EntityDropdown/EntityDropdown.tsx +110 -2
  141. package/UI/Components/ErrorBoundary.tsx +2 -1
  142. package/UI/Components/EventItem/EventItem.tsx +2 -2
  143. package/UI/Components/GanttChart/Bar/Index.tsx +1 -1
  144. package/UI/Components/Graphs/UptimeBarTooltip.tsx +30 -23
  145. package/UI/Components/Header/Header.tsx +7 -0
  146. package/UI/Components/Header/HeaderIconDropdownButton.tsx +2 -0
  147. package/UI/Components/Icon/Icon.tsx +8 -6
  148. package/UI/Components/Label/Label.tsx +2 -2
  149. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +22 -10
  150. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +9 -3
  151. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +8 -8
  152. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +44 -20
  153. package/UI/Components/Modal/ConfirmModal.tsx +1 -1
  154. package/UI/Components/Modal/Modal.tsx +213 -121
  155. package/UI/Components/Modal/ModalFooter.tsx +33 -22
  156. package/UI/Components/ModelTable/TableView.tsx +1 -1
  157. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +20 -12
  158. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +2 -2
  159. package/UI/Components/Pill/Pill.tsx +21 -13
  160. package/UI/Components/StatusBubble/StatusBubble.tsx +3 -3
  161. package/UI/Components/Tabs/Tabs.tsx +10 -1
  162. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +7 -1
  163. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +9 -3
  164. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +62 -4
  165. package/UI/Components/Workflow/Component.tsx +53 -33
  166. package/UI/Components/Workflow/ComponentPortViewer.tsx +6 -6
  167. package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +8 -8
  168. package/UI/Components/Workflow/ComponentsModal.tsx +16 -9
  169. package/UI/Components/Workflow/Workflow.tsx +13 -11
  170. package/UI/Utils/Navigation.ts +10 -1
  171. package/UI/Utils/Theme.ts +140 -0
  172. package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +99 -0
  173. package/Utils/Dashboard/Components/Index.ts +7 -0
  174. package/Utils/Monitor/LatencyMatrixUtil.ts +162 -0
  175. package/Utils/Monitor/MonitorMetricType.ts +141 -3
  176. package/Utils/Monitor/NetworkTopologyUtil.ts +159 -0
  177. package/Utils/Telemetry/EntityRelationship.ts +11 -0
  178. package/build/dist/Models/DatabaseModels/AIRun.js +52 -0
  179. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/AlertSeverity.js +6 -0
  181. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +6 -0
  183. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  185. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js +493 -0
  187. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js.map +1 -0
  188. package/build/dist/Models/DatabaseModels/LlmLog.js +58 -0
  189. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/LlmProvider.js +33 -0
  191. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/NetworkDevice.js +1426 -0
  193. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -0
  194. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +738 -0
  195. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -0
  196. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js +522 -0
  197. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js.map +1 -0
  198. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js +603 -0
  199. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js.map +1 -0
  200. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +503 -0
  201. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -0
  202. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +502 -0
  203. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -0
  204. package/build/dist/Models/DatabaseModels/NetworkInterface.js +589 -0
  205. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -0
  206. package/build/dist/Models/DatabaseModels/Project.js +147 -0
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +57 -0
  209. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -1
  210. package/build/dist/Server/API/AIAgentTaskAPI.js +8 -23
  211. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
  212. package/build/dist/Server/API/AIInvestigationAPI.js +95 -55
  213. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  214. package/build/dist/Server/API/AlertAPI.js +5 -0
  215. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  216. package/build/dist/Server/API/IncidentAPI.js +10 -0
  217. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  218. package/build/dist/Server/API/IncidentEpisodeAPI.js +5 -0
  219. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  220. package/build/dist/Server/API/LlmProviderAPI.js +5 -7
  221. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  222. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +5 -0
  223. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  224. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  225. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js +12 -0
  226. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js.map +1 -0
  227. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js +14 -0
  228. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js.map +1 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js +18 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js.map +1 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js +12 -0
  232. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js.map +1 -0
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js +51 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js +12 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js +101 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js +18 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js +12 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js +14 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js.map +1 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js +16 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js.map +1 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js +38 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js.map +1 -0
  249. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js +22 -0
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js.map +1 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +24 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  253. package/build/dist/Server/Services/AIAgentTaskService.js +59 -0
  254. package/build/dist/Server/Services/AIAgentTaskService.js.map +1 -1
  255. package/build/dist/Server/Services/AIRunService.js +33 -0
  256. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  257. package/build/dist/Server/Services/AIService.js +82 -9
  258. package/build/dist/Server/Services/AIService.js.map +1 -1
  259. package/build/dist/Server/Services/AnalyticsDatabaseService.js +19 -0
  260. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  261. package/build/dist/Server/Services/IncidentService.js +14 -25
  262. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  263. package/build/dist/Server/Services/Index.js +14 -0
  264. package/build/dist/Server/Services/Index.js.map +1 -1
  265. package/build/dist/Server/Services/IoTDeviceCredentialService.js +321 -0
  266. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -0
  267. package/build/dist/Server/Services/IoTDeviceService.js +49 -15
  268. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  269. package/build/dist/Server/Services/LlmLogService.js +29 -0
  270. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  271. package/build/dist/Server/Services/LlmProviderService.js +3 -0
  272. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  273. package/build/dist/Server/Services/LogAggregationService.js +21 -7
  274. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  275. package/build/dist/Server/Services/MetricService.js +449 -7
  276. package/build/dist/Server/Services/MetricService.js.map +1 -1
  277. package/build/dist/Server/Services/MonitorService.js +2 -1
  278. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  279. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +9 -0
  280. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -0
  281. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +166 -0
  282. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -0
  283. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js +13 -0
  284. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js.map +1 -0
  285. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +186 -0
  286. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -0
  287. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js +13 -0
  288. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js.map +1 -0
  289. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +9 -0
  290. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -0
  291. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +9 -0
  292. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -0
  293. package/build/dist/Server/Services/NetworkDeviceService.js +52 -0
  294. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -0
  295. package/build/dist/Server/Services/NetworkInterfaceService.js +9 -0
  296. package/build/dist/Server/Services/NetworkInterfaceService.js.map +1 -0
  297. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +22 -0
  298. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  299. package/build/dist/Server/Services/TelemetryEntityService.js +64 -2
  300. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  301. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js +189 -9
  302. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +1 -1
  303. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +84 -17
  304. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +1 -1
  305. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js +428 -0
  306. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +1 -0
  307. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js +63 -47
  308. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -1
  310. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  311. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +300 -0
  312. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
  313. package/build/dist/Server/Utils/LLM/LLMService.js +16 -0
  314. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  315. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +29 -0
  316. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  317. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +130 -2
  318. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  319. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js +81 -0
  320. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js.map +1 -0
  321. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +18 -7
  322. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  323. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
  324. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  325. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +25 -10
  326. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  327. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +155 -5
  328. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  329. package/build/dist/Server/Utils/Monitor/MonitorResource.js +76 -30
  330. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  331. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -1
  332. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  333. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +147 -0
  334. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -0
  335. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +167 -0
  336. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -0
  337. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +93 -0
  338. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -0
  339. package/build/dist/Types/AI/AIRunStatus.js +9 -0
  340. package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
  341. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  342. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js +2 -0
  344. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js.map +1 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js +9 -1
  346. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  347. package/build/dist/Types/LlmLogStatus.js +1 -0
  348. package/build/dist/Types/LlmLogStatus.js.map +1 -1
  349. package/build/dist/Types/Monitor/CriteriaFilter.js +9 -0
  350. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  351. package/build/dist/Types/Monitor/HttpPhaseTimings.js +2 -0
  352. package/build/dist/Types/Monitor/HttpPhaseTimings.js.map +1 -0
  353. package/build/dist/Types/Monitor/IotAlertTemplates.js +7 -7
  354. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  355. package/build/dist/Types/Monitor/LatencyMatrix.js +2 -0
  356. package/build/dist/Types/Monitor/LatencyMatrix.js.map +1 -0
  357. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +2 -2
  358. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  359. package/build/dist/Types/Monitor/MonitorMetricType.js +24 -0
  360. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  361. package/build/dist/Types/Monitor/MonitorStep.js +22 -9
  362. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  363. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +36 -0
  364. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -0
  365. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -0
  366. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
  367. package/build/dist/Types/Monitor/MonitorType.js +14 -9
  368. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  369. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js +2 -0
  370. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js.map +1 -0
  371. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js +2 -0
  372. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js.map +1 -0
  373. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +89 -0
  374. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -0
  375. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js +2 -0
  376. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js.map +1 -0
  377. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js +2 -0
  378. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js.map +1 -0
  379. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js +2 -0
  380. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js.map +1 -0
  381. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +137 -0
  382. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -0
  383. package/build/dist/Types/Permission.js +280 -0
  384. package/build/dist/Types/Permission.js.map +1 -1
  385. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +7 -4
  386. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  387. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +4 -1
  388. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  389. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +6 -3
  390. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  391. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +1 -1
  392. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  393. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +3 -1
  394. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  395. package/build/dist/UI/Components/Divider/Divider.js +1 -1
  396. package/build/dist/UI/Components/Divider/Divider.js.map +1 -1
  397. package/build/dist/UI/Components/Dropdown/Dropdown.js +10 -4
  398. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  399. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +76 -3
  400. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  401. package/build/dist/UI/Components/ErrorBoundary.js +2 -1
  402. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  403. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  404. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  405. package/build/dist/UI/Components/GanttChart/Bar/Index.js +1 -1
  406. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +1 -1
  407. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +29 -23
  408. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  409. package/build/dist/UI/Components/Header/Header.js +1 -0
  410. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  411. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  412. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  413. package/build/dist/UI/Components/Icon/Icon.js +8 -6
  414. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  415. package/build/dist/UI/Components/Label/Label.js +2 -2
  416. package/build/dist/UI/Components/Label/Label.js.map +1 -1
  417. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +20 -8
  418. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  419. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +8 -2
  420. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  421. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +8 -8
  422. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +40 -20
  423. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  424. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  425. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  426. package/build/dist/UI/Components/Modal/Modal.js +109 -51
  427. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  428. package/build/dist/UI/Components/Modal/ModalFooter.js +13 -10
  429. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  430. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  431. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  432. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +17 -12
  433. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  434. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -2
  435. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  436. package/build/dist/UI/Components/Pill/Pill.js +12 -13
  437. package/build/dist/UI/Components/Pill/Pill.js.map +1 -1
  438. package/build/dist/UI/Components/StatusBubble/StatusBubble.js +3 -3
  439. package/build/dist/UI/Components/StatusBubble/StatusBubble.js.map +1 -1
  440. package/build/dist/UI/Components/Tabs/Tabs.js +3 -1
  441. package/build/dist/UI/Components/Tabs/Tabs.js.map +1 -1
  442. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  443. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  444. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -2
  445. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  446. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +36 -6
  447. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  448. package/build/dist/UI/Components/Workflow/Component.js +43 -33
  449. package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
  450. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js +6 -6
  451. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js.map +1 -1
  452. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +8 -8
  453. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
  454. package/build/dist/UI/Components/Workflow/ComponentsModal.js +15 -9
  455. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  456. package/build/dist/UI/Components/Workflow/Workflow.js +13 -11
  457. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  458. package/build/dist/UI/Utils/Navigation.js +11 -1
  459. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  460. package/build/dist/UI/Utils/Theme.js +106 -0
  461. package/build/dist/UI/Utils/Theme.js.map +1 -0
  462. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +89 -0
  463. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -0
  464. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  465. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  466. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js +89 -0
  467. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js.map +1 -0
  468. package/build/dist/Utils/Monitor/MonitorMetricType.js +138 -4
  469. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  470. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +112 -0
  471. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -0
  472. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  473. package/package.json +1 -1
@@ -0,0 +1,360 @@
1
+ import SentinelAlertInvestigationRunner, {
2
+ AlertGateDecision,
3
+ } from "../../../../Server/Utils/AI/Sentinel/AlertInvestigationRunner";
4
+ import SentinelInvestigationQueue from "../../../../Server/Utils/AI/Sentinel/InvestigationQueue";
5
+ import AlertService from "../../../../Server/Services/AlertService";
6
+ import AlertSeverityService from "../../../../Server/Services/AlertSeverityService";
7
+ import ProjectService from "../../../../Server/Services/ProjectService";
8
+ import AIRunService from "../../../../Server/Services/AIRunService";
9
+ import Alert from "../../../../Models/DatabaseModels/Alert";
10
+ import AlertSeverity from "../../../../Models/DatabaseModels/AlertSeverity";
11
+ import Project from "../../../../Models/DatabaseModels/Project";
12
+ import ObjectID from "../../../../Types/ObjectID";
13
+ import PositiveNumber from "../../../../Types/PositiveNumber";
14
+ import { describe, expect, test, afterEach } from "@jest/globals";
15
+
16
+ /*
17
+ * Cost gates for autonomous alert investigations (Phase 1 / G4):
18
+ * - severity floor: explicit per-project minimum severity, defaulting to the
19
+ * project's top two tiers (lowest two `order` values; lower order = higher
20
+ * severity);
21
+ * - per-monitor dedupe window: a monitor already investigated within the
22
+ * window is not re-investigated;
23
+ * - per-project concurrency cap in the shared engine.
24
+ *
25
+ * These tests mock the persistence layer (no Postgres) to lock in the gate
26
+ * decisions and their fail directions: unknown severity PASSES the severity
27
+ * gate (it only filters known-low-severity noise), while a failed cap check
28
+ * SKIPS (a cost gate fails cheap).
29
+ */
30
+
31
+ function fakeAlert(data: {
32
+ monitorId?: ObjectID | undefined;
33
+ severityOrder?: number | undefined;
34
+ }): Alert {
35
+ return {
36
+ id: ObjectID.generate(),
37
+ monitorId: data.monitorId,
38
+ alertSeverity:
39
+ data.severityOrder !== undefined
40
+ ? ({ order: data.severityOrder } as AlertSeverity)
41
+ : undefined,
42
+ } as unknown as Alert;
43
+ }
44
+
45
+ function fakeProject(
46
+ minimumSeverityId?: ObjectID | undefined,
47
+ dedupeWindowMinutes?: number | undefined,
48
+ ): Project {
49
+ return {
50
+ id: ObjectID.generate(),
51
+ alertInvestigationMinimumSeverityId: minimumSeverityId,
52
+ alertInvestigationDedupeWindowMinutes: dedupeWindowMinutes,
53
+ } as unknown as Project;
54
+ }
55
+
56
+ function fakeSeverities(orders: Array<number>): Array<AlertSeverity> {
57
+ return orders.map((order: number) => {
58
+ return { order } as AlertSeverity;
59
+ });
60
+ }
61
+
62
+ describe("SentinelAlertInvestigationRunner.shouldInvestigateAlert", () => {
63
+ const alertId: ObjectID = ObjectID.generate();
64
+ const projectId: ObjectID = ObjectID.generate();
65
+
66
+ afterEach(() => {
67
+ jest.restoreAllMocks();
68
+ });
69
+
70
+ function mockGates(data: {
71
+ alert: Alert | null;
72
+ project?: Project;
73
+ explicitFloorSeverity?: AlertSeverity | null;
74
+ topTiers?: Array<AlertSeverity>;
75
+ recentRunCount?: number;
76
+ }): void {
77
+ jest.spyOn(AlertService, "findOneById").mockResolvedValue(data.alert);
78
+ jest
79
+ .spyOn(ProjectService, "findOneById")
80
+ .mockResolvedValue(data.project || fakeProject());
81
+ jest
82
+ .spyOn(AlertSeverityService, "findOneById")
83
+ .mockResolvedValue(data.explicitFloorSeverity ?? null);
84
+ jest
85
+ .spyOn(AlertSeverityService, "findBy")
86
+ .mockResolvedValue(data.topTiers || []);
87
+ jest
88
+ .spyOn(AIRunService, "countBy")
89
+ .mockResolvedValue(new PositiveNumber(data.recentRunCount || 0));
90
+ }
91
+
92
+ test("skips when severity is below an explicitly configured floor", async () => {
93
+ const floorSeverityId: ObjectID = ObjectID.generate();
94
+ mockGates({
95
+ alert: fakeAlert({ severityOrder: 3 }),
96
+ project: fakeProject(floorSeverityId),
97
+ explicitFloorSeverity: { order: 2 } as AlertSeverity,
98
+ });
99
+
100
+ const decision: AlertGateDecision =
101
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
102
+ alertId,
103
+ projectId,
104
+ });
105
+
106
+ expect(decision.investigate).toBe(false);
107
+ expect(decision.reason).toContain("below the investigation floor");
108
+ });
109
+
110
+ test("investigates when severity meets the explicit floor and no recent run exists", async () => {
111
+ const monitorId: ObjectID = ObjectID.generate();
112
+ const floorSeverityId: ObjectID = ObjectID.generate();
113
+ mockGates({
114
+ alert: fakeAlert({ severityOrder: 2, monitorId }),
115
+ project: fakeProject(floorSeverityId),
116
+ explicitFloorSeverity: { order: 2 } as AlertSeverity,
117
+ recentRunCount: 0,
118
+ });
119
+
120
+ const decision: AlertGateDecision =
121
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
122
+ alertId,
123
+ projectId,
124
+ });
125
+
126
+ expect(decision.investigate).toBe(true);
127
+ expect(decision.monitorId).toBe(monitorId);
128
+ });
129
+
130
+ test("default floor is the top two tiers: third tier is skipped", async () => {
131
+ mockGates({
132
+ alert: fakeAlert({ severityOrder: 3 }),
133
+ topTiers: fakeSeverities([1, 2]),
134
+ });
135
+
136
+ const decision: AlertGateDecision =
137
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
138
+ alertId,
139
+ projectId,
140
+ });
141
+
142
+ expect(decision.investigate).toBe(false);
143
+ });
144
+
145
+ test("default floor: second tier is investigated", async () => {
146
+ mockGates({
147
+ alert: fakeAlert({ severityOrder: 2 }),
148
+ topTiers: fakeSeverities([1, 2]),
149
+ });
150
+
151
+ const decision: AlertGateDecision =
152
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
153
+ alertId,
154
+ projectId,
155
+ });
156
+
157
+ expect(decision.investigate).toBe(true);
158
+ });
159
+
160
+ test("a deleted explicit floor severity falls back to the top-two default", async () => {
161
+ // Project points at a severity that no longer exists (findOneById → null).
162
+ mockGates({
163
+ alert: fakeAlert({ severityOrder: 3 }),
164
+ project: fakeProject(ObjectID.generate()),
165
+ explicitFloorSeverity: null,
166
+ topTiers: fakeSeverities([1, 2]),
167
+ });
168
+
169
+ const decision: AlertGateDecision =
170
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
171
+ alertId,
172
+ projectId,
173
+ });
174
+
175
+ expect(decision.investigate).toBe(false);
176
+ });
177
+
178
+ test("unknown alert severity passes the severity gate", async () => {
179
+ mockGates({
180
+ alert: fakeAlert({ severityOrder: undefined }),
181
+ topTiers: fakeSeverities([1, 2]),
182
+ });
183
+
184
+ const decision: AlertGateDecision =
185
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
186
+ alertId,
187
+ projectId,
188
+ });
189
+
190
+ expect(decision.investigate).toBe(true);
191
+ });
192
+
193
+ test("skips when the monitor was already investigated within the window", async () => {
194
+ const monitorId: ObjectID = ObjectID.generate();
195
+ const countBy: jest.SpyInstance = jest.spyOn(AIRunService, "countBy");
196
+
197
+ mockGates({
198
+ alert: fakeAlert({ severityOrder: 1, monitorId }),
199
+ topTiers: fakeSeverities([1, 2]),
200
+ recentRunCount: 1,
201
+ });
202
+
203
+ const decision: AlertGateDecision =
204
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
205
+ alertId,
206
+ projectId,
207
+ });
208
+
209
+ expect(decision.investigate).toBe(false);
210
+ expect(decision.reason).toContain("already investigated");
211
+ expect(countBy).toHaveBeenCalledWith(
212
+ expect.objectContaining({
213
+ query: expect.objectContaining({
214
+ monitorId,
215
+ }),
216
+ }),
217
+ );
218
+ });
219
+
220
+ test("alerts without a monitor skip the dedupe check entirely", async () => {
221
+ const countBy: jest.SpyInstance = jest.spyOn(AIRunService, "countBy");
222
+
223
+ mockGates({
224
+ alert: fakeAlert({ severityOrder: 1 }),
225
+ topTiers: fakeSeverities([1, 2]),
226
+ });
227
+
228
+ const decision: AlertGateDecision =
229
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
230
+ alertId,
231
+ projectId,
232
+ });
233
+
234
+ expect(decision.investigate).toBe(true);
235
+ expect(countBy).not.toHaveBeenCalled();
236
+ });
237
+
238
+ test("a cooldown of 0 disables the dedupe check entirely", async () => {
239
+ const monitorId: ObjectID = ObjectID.generate();
240
+ const countBy: jest.SpyInstance = jest.spyOn(AIRunService, "countBy");
241
+
242
+ mockGates({
243
+ alert: fakeAlert({ severityOrder: 1, monitorId }),
244
+ project: fakeProject(undefined, 0),
245
+ topTiers: fakeSeverities([1, 2]),
246
+ recentRunCount: 1,
247
+ });
248
+
249
+ const decision: AlertGateDecision =
250
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
251
+ alertId,
252
+ projectId,
253
+ });
254
+
255
+ expect(decision.investigate).toBe(true);
256
+ expect(countBy).not.toHaveBeenCalled();
257
+ });
258
+
259
+ test("a custom cooldown is used for the dedupe window", async () => {
260
+ const monitorId: ObjectID = ObjectID.generate();
261
+
262
+ mockGates({
263
+ alert: fakeAlert({ severityOrder: 1, monitorId }),
264
+ project: fakeProject(undefined, 45),
265
+ topTiers: fakeSeverities([1, 2]),
266
+ recentRunCount: 1,
267
+ });
268
+
269
+ const decision: AlertGateDecision =
270
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
271
+ alertId,
272
+ projectId,
273
+ });
274
+
275
+ expect(decision.investigate).toBe(false);
276
+ expect(decision.reason).toContain("within the last 45 minutes");
277
+ });
278
+
279
+ test("skips when the alert cannot be found", async () => {
280
+ mockGates({ alert: null });
281
+
282
+ const decision: AlertGateDecision =
283
+ await SentinelAlertInvestigationRunner.shouldInvestigateAlert({
284
+ alertId,
285
+ projectId,
286
+ });
287
+
288
+ expect(decision.investigate).toBe(false);
289
+ });
290
+ });
291
+
292
+ describe("SentinelInvestigationQueue concurrency cap", () => {
293
+ beforeEach(() => {
294
+ // No per-project override => the default cap of 3 applies.
295
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue(fakeProject());
296
+ });
297
+
298
+ afterEach(() => {
299
+ jest.restoreAllMocks();
300
+ });
301
+
302
+ test("leaves the run queued when the per-project cap is reached", async () => {
303
+ jest
304
+ .spyOn(AIRunService, "countBy")
305
+ .mockResolvedValue(new PositiveNumber(3));
306
+ const claim: jest.SpyInstance = jest.spyOn(
307
+ AIRunService,
308
+ "attemptStatusTransition",
309
+ );
310
+
311
+ await SentinelInvestigationQueue.processRun({
312
+ id: ObjectID.generate(),
313
+ projectId: ObjectID.generate(),
314
+ attemptCount: 0,
315
+ triggeredByAlertId: ObjectID.generate(),
316
+ });
317
+
318
+ expect(claim).not.toHaveBeenCalled();
319
+ });
320
+
321
+ test("leaves the run queued when the cap check itself fails", async () => {
322
+ jest.spyOn(AIRunService, "countBy").mockRejectedValue(new Error("db down"));
323
+ const claim: jest.SpyInstance = jest.spyOn(
324
+ AIRunService,
325
+ "attemptStatusTransition",
326
+ );
327
+
328
+ await SentinelInvestigationQueue.processRun({
329
+ id: ObjectID.generate(),
330
+ projectId: ObjectID.generate(),
331
+ attemptCount: 0,
332
+ triggeredByAlertId: ObjectID.generate(),
333
+ });
334
+
335
+ expect(claim).not.toHaveBeenCalled();
336
+ });
337
+
338
+ test("a per-project cap override of 1 blocks the second concurrent run", async () => {
339
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
340
+ id: ObjectID.generate(),
341
+ aiMaxConcurrentInvestigations: 1,
342
+ } as unknown as Project);
343
+ jest
344
+ .spyOn(AIRunService, "countBy")
345
+ .mockResolvedValue(new PositiveNumber(1));
346
+ const claim: jest.SpyInstance = jest.spyOn(
347
+ AIRunService,
348
+ "attemptStatusTransition",
349
+ );
350
+
351
+ await SentinelInvestigationQueue.processRun({
352
+ id: ObjectID.generate(),
353
+ projectId: ObjectID.generate(),
354
+ attemptCount: 0,
355
+ triggeredByAlertId: ObjectID.generate(),
356
+ });
357
+
358
+ expect(claim).not.toHaveBeenCalled();
359
+ });
360
+ });
@@ -0,0 +1,295 @@
1
+ import SentinelInvestigationQueue, {
2
+ MAX_INVESTIGATION_ATTEMPTS,
3
+ } from "../../../../Server/Utils/AI/Sentinel/InvestigationQueue";
4
+ import SentinelIncidentInvestigationRunner from "../../../../Server/Utils/AI/Sentinel/IncidentInvestigationRunner";
5
+ import SentinelAlertInvestigationRunner from "../../../../Server/Utils/AI/Sentinel/AlertInvestigationRunner";
6
+ import AIRunService from "../../../../Server/Services/AIRunService";
7
+ import AIService from "../../../../Server/Services/AIService";
8
+ import ProjectService from "../../../../Server/Services/ProjectService";
9
+ import Project from "../../../../Models/DatabaseModels/Project";
10
+ import AIRun from "../../../../Models/DatabaseModels/AIRun";
11
+ import AIRunStatus from "../../../../Types/AI/AIRunStatus";
12
+ import ObjectID from "../../../../Types/ObjectID";
13
+ import PositiveNumber from "../../../../Types/PositiveNumber";
14
+ import { describe, expect, test, afterEach, beforeEach } from "@jest/globals";
15
+
16
+ /*
17
+ * The durable investigation queue (Phase 2's first item — replaces detached
18
+ * fire-and-forget investigations that a pod restart could orphan, D2).
19
+ *
20
+ * The invariants these tests lock in:
21
+ * (a) enqueue records a Queued AIRun (the durable intent) before any
22
+ * expensive work, and kicks inline processing;
23
+ * (b) the claim is a status-guarded CAS: a lost claim never executes,
24
+ * a won claim increments attemptCount and dispatches to the right
25
+ * subject runner;
26
+ * (c) the retry policy (G9): transient failures requeue while attempts
27
+ * remain; permanent failures and exhausted attempts finalize as
28
+ * Error — and the CAS guard means an already-Completed run is never
29
+ * clobbered;
30
+ * (d) heartbeat-stale runs requeue while attempts remain, else go Stale;
31
+ * (e) the poller expires runs that queued past their usefulness window.
32
+ */
33
+
34
+ function mockBudgetOk(): void {
35
+ jest.spyOn(AIService, "getAutonomousDailyBudgetStatus").mockResolvedValue({
36
+ exhausted: false,
37
+ limitInTokens: null,
38
+ usedTokensToday: 0,
39
+ });
40
+ }
41
+
42
+ describe("SentinelInvestigationQueue", () => {
43
+ beforeEach(() => {
44
+ mockBudgetOk();
45
+ // No per-project cap override => default of 3.
46
+ jest
47
+ .spyOn(ProjectService, "findOneById")
48
+ .mockResolvedValue({ id: ObjectID.generate() } as unknown as Project);
49
+ // No investigations currently running (cap check passes).
50
+ jest
51
+ .spyOn(AIRunService, "countBy")
52
+ .mockResolvedValue(new PositiveNumber(0));
53
+ });
54
+
55
+ afterEach(() => {
56
+ jest.restoreAllMocks();
57
+ });
58
+
59
+ test("enqueue records a Queued run with the subject and kicks processing", async () => {
60
+ const projectId: ObjectID = ObjectID.generate();
61
+ const incidentId: ObjectID = ObjectID.generate();
62
+ const createdId: ObjectID = ObjectID.generate();
63
+
64
+ const create: jest.SpyInstance = jest
65
+ .spyOn(AIRunService, "create")
66
+ .mockResolvedValue({ id: createdId } as unknown as AIRun);
67
+ const processRun: jest.SpyInstance = jest
68
+ .spyOn(SentinelInvestigationQueue, "processRun")
69
+ .mockResolvedValue(undefined);
70
+
71
+ await SentinelInvestigationQueue.enqueue({
72
+ projectId,
73
+ subjectIncidentId: incidentId,
74
+ });
75
+
76
+ expect(create).toHaveBeenCalledWith(
77
+ expect.objectContaining({
78
+ data: expect.objectContaining({
79
+ status: AIRunStatus.Queued,
80
+ triggeredByIncidentId: incidentId,
81
+ }),
82
+ }),
83
+ );
84
+ // The inline kick is detached; give the microtask a beat.
85
+ await new Promise((resolve: (value: unknown) => void) => {
86
+ setTimeout(resolve, 0);
87
+ });
88
+ expect(processRun).toHaveBeenCalledWith(
89
+ expect.objectContaining({
90
+ id: createdId,
91
+ attemptCount: 0,
92
+ triggeredByIncidentId: incidentId,
93
+ }),
94
+ );
95
+ });
96
+
97
+ test("a lost claim never executes the investigation", async () => {
98
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(0);
99
+ const execute: jest.SpyInstance = jest.spyOn(
100
+ SentinelIncidentInvestigationRunner,
101
+ "executeInvestigation",
102
+ );
103
+
104
+ await SentinelInvestigationQueue.processRun({
105
+ id: ObjectID.generate(),
106
+ projectId: ObjectID.generate(),
107
+ attemptCount: 0,
108
+ triggeredByIncidentId: ObjectID.generate(),
109
+ });
110
+
111
+ expect(execute).not.toHaveBeenCalled();
112
+ });
113
+
114
+ test("a won claim increments attemptCount and dispatches to the incident runner", async () => {
115
+ const runId: ObjectID = ObjectID.generate();
116
+ const incidentId: ObjectID = ObjectID.generate();
117
+ const claim: jest.SpyInstance = jest
118
+ .spyOn(AIRunService, "attemptStatusTransition")
119
+ .mockResolvedValue(1);
120
+ const execute: jest.SpyInstance = jest
121
+ .spyOn(SentinelIncidentInvestigationRunner, "executeInvestigation")
122
+ .mockResolvedValue(undefined);
123
+
124
+ await SentinelInvestigationQueue.processRun({
125
+ id: runId,
126
+ projectId: ObjectID.generate(),
127
+ attemptCount: 0,
128
+ triggeredByIncidentId: incidentId,
129
+ });
130
+
131
+ expect(claim).toHaveBeenCalledWith(
132
+ expect.objectContaining({
133
+ aiRunId: runId,
134
+ fromStatus: AIRunStatus.Queued,
135
+ // Guards against stale queue snapshots re-claiming or re-numbering.
136
+ expectedAttemptCount: 0,
137
+ set: expect.objectContaining({
138
+ status: AIRunStatus.Running,
139
+ attemptCount: 1,
140
+ }),
141
+ }),
142
+ );
143
+ expect(execute).toHaveBeenCalledWith(
144
+ expect.objectContaining({
145
+ aiRunId: runId,
146
+ incidentId,
147
+ attemptCount: 1,
148
+ }),
149
+ );
150
+ });
151
+
152
+ test("a won claim dispatches alert runs to the alert runner", async () => {
153
+ const alertId: ObjectID = ObjectID.generate();
154
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
155
+ const execute: jest.SpyInstance = jest
156
+ .spyOn(SentinelAlertInvestigationRunner, "executeInvestigation")
157
+ .mockResolvedValue(undefined);
158
+
159
+ await SentinelInvestigationQueue.processRun({
160
+ id: ObjectID.generate(),
161
+ projectId: ObjectID.generate(),
162
+ attemptCount: 0,
163
+ triggeredByAlertId: alertId,
164
+ });
165
+
166
+ expect(execute).toHaveBeenCalledWith(
167
+ expect.objectContaining({ alertId, attemptCount: 1 }),
168
+ );
169
+ });
170
+
171
+ test("a transient failure on the first attempt requeues the run", async () => {
172
+ const runId: ObjectID = ObjectID.generate();
173
+ const update: jest.SpyInstance = jest
174
+ .spyOn(AIRunService, "attemptStatusTransition")
175
+ .mockResolvedValue(1);
176
+
177
+ await SentinelInvestigationQueue.failOrRequeue({
178
+ aiRunId: runId,
179
+ attemptCount: 1,
180
+ errorMessage: "LLM provider timed out",
181
+ isPermanent: false,
182
+ });
183
+
184
+ expect(update).toHaveBeenCalledWith(
185
+ expect.objectContaining({
186
+ aiRunId: runId,
187
+ fromStatus: AIRunStatus.Running,
188
+ set: expect.objectContaining({
189
+ status: AIRunStatus.Queued,
190
+ }),
191
+ }),
192
+ );
193
+ });
194
+
195
+ test("a transient failure on the final attempt finalizes as Error", async () => {
196
+ const update: jest.SpyInstance = jest
197
+ .spyOn(AIRunService, "attemptStatusTransition")
198
+ .mockResolvedValue(1);
199
+
200
+ await SentinelInvestigationQueue.failOrRequeue({
201
+ aiRunId: ObjectID.generate(),
202
+ attemptCount: MAX_INVESTIGATION_ATTEMPTS,
203
+ errorMessage: "LLM provider timed out",
204
+ isPermanent: false,
205
+ });
206
+
207
+ expect(update).toHaveBeenCalledWith(
208
+ expect.objectContaining({
209
+ set: expect.objectContaining({
210
+ status: AIRunStatus.Error,
211
+ }),
212
+ }),
213
+ );
214
+ });
215
+
216
+ test("a permanent failure never retries, even with attempts remaining", async () => {
217
+ const update: jest.SpyInstance = jest
218
+ .spyOn(AIRunService, "attemptStatusTransition")
219
+ .mockResolvedValue(1);
220
+
221
+ await SentinelInvestigationQueue.failOrRequeue({
222
+ aiRunId: ObjectID.generate(),
223
+ attemptCount: 1,
224
+ errorMessage: "No LLM provider configured for this project.",
225
+ isPermanent: true,
226
+ });
227
+
228
+ expect(update).toHaveBeenCalledTimes(1);
229
+ expect(update).toHaveBeenCalledWith(
230
+ expect.objectContaining({
231
+ set: expect.objectContaining({
232
+ status: AIRunStatus.Error,
233
+ }),
234
+ }),
235
+ );
236
+ });
237
+
238
+ test("a heartbeat-stale run requeues while attempts remain", async () => {
239
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
240
+
241
+ const outcome: "requeued" | "stale" =
242
+ await SentinelInvestigationQueue.requeueOrMarkStale({
243
+ id: ObjectID.generate(),
244
+ attemptCount: 1,
245
+ });
246
+
247
+ expect(outcome).toBe("requeued");
248
+ });
249
+
250
+ test("a heartbeat-stale run out of attempts is marked Stale", async () => {
251
+ const update: jest.SpyInstance = jest
252
+ .spyOn(AIRunService, "attemptStatusTransition")
253
+ .mockResolvedValue(1);
254
+
255
+ const outcome: "requeued" | "stale" =
256
+ await SentinelInvestigationQueue.requeueOrMarkStale({
257
+ id: ObjectID.generate(),
258
+ attemptCount: MAX_INVESTIGATION_ATTEMPTS,
259
+ });
260
+
261
+ expect(outcome).toBe("stale");
262
+ expect(update).toHaveBeenCalledWith(
263
+ expect.objectContaining({
264
+ set: expect.objectContaining({
265
+ status: AIRunStatus.Stale,
266
+ }),
267
+ }),
268
+ );
269
+ });
270
+
271
+ test("the poller expires runs queued past the usefulness window", async () => {
272
+ const expiredId: ObjectID = ObjectID.generate();
273
+ const findBy: jest.SpyInstance = jest
274
+ .spyOn(AIRunService, "findBy")
275
+ // First call: expired runs. Second call: nothing left to drain.
276
+ .mockResolvedValueOnce([{ id: expiredId } as unknown as AIRun])
277
+ .mockResolvedValueOnce([]);
278
+ const update: jest.SpyInstance = jest
279
+ .spyOn(AIRunService, "attemptStatusTransition")
280
+ .mockResolvedValue(1);
281
+
282
+ await SentinelInvestigationQueue.processQueuedRuns();
283
+
284
+ expect(findBy).toHaveBeenCalledTimes(2);
285
+ expect(update).toHaveBeenCalledWith(
286
+ expect.objectContaining({
287
+ aiRunId: expiredId,
288
+ fromStatus: AIRunStatus.Queued,
289
+ set: expect.objectContaining({
290
+ status: AIRunStatus.Cancelled,
291
+ }),
292
+ }),
293
+ );
294
+ });
295
+ });