@oneuptime/common 9.2.27 → 9.3.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 (263) hide show
  1. package/Models/DatabaseModels/AIAgent.ts +589 -0
  2. package/Models/DatabaseModels/AIAgentOwnerTeam.ts +434 -0
  3. package/Models/DatabaseModels/AIAgentOwnerUser.ts +433 -0
  4. package/Models/DatabaseModels/AIAgentTask.ts +549 -0
  5. package/Models/DatabaseModels/AIAgentTaskLog.ts +417 -0
  6. package/Models/DatabaseModels/AIAgentTaskPullRequest.ts +731 -0
  7. package/Models/DatabaseModels/AIAgentTaskTelemetryException.ts +388 -0
  8. package/Models/DatabaseModels/Index.ts +15 -0
  9. package/Models/DatabaseModels/Monitor.ts +33 -0
  10. package/Models/DatabaseModels/Project.ts +25 -0
  11. package/Models/DatabaseModels/TelemetryException.ts +1 -1
  12. package/Server/API/AIAgentAPI.ts +200 -0
  13. package/Server/API/AIAgentDataAPI.ts +692 -0
  14. package/Server/API/AIAgentTaskAPI.ts +286 -0
  15. package/Server/API/AIAgentTaskLogAPI.ts +165 -0
  16. package/Server/API/AIAgentTaskPullRequestAPI.ts +14 -0
  17. package/Server/API/GitHubAPI.ts +25 -7
  18. package/Server/API/TelemetryExceptionAPI.ts +169 -0
  19. package/Server/EnvironmentConfig.ts +3 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1766590916627-MigrationName.ts +195 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1766600860972-MigrationName.ts +31 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1766606720183-MigrationName.ts +17 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1766688107858-MigrationName.ts +63 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1766754182870-MigrationName.ts +75 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1766774689743-MigrationName.ts +157 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1766777986427-MigrationName.ts +33 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1766918848434-AddAIAgentIsDefault.ts +27 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1766923324521-MigrationName.ts +37 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1766958924188-AddGitHubAppInstallationIdToProject.ts +31 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1767009661768-MigrationName.ts +35 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +22 -0
  32. package/Server/Services/AIAgentOwnerTeamService.ts +10 -0
  33. package/Server/Services/AIAgentOwnerUserService.ts +10 -0
  34. package/Server/Services/AIAgentService.ts +564 -0
  35. package/Server/Services/AIAgentTaskLogService.ts +10 -0
  36. package/Server/Services/AIAgentTaskPullRequestService.ts +10 -0
  37. package/Server/Services/AIAgentTaskService.ts +178 -0
  38. package/Server/Services/AIAgentTaskTelemetryExceptionService.ts +39 -0
  39. package/Server/Services/Index.ts +10 -0
  40. package/Server/Services/TelemetryExceptionService.ts +162 -0
  41. package/Server/Utils/Monitor/MonitorResource.ts +228 -0
  42. package/Server/Utils/PushNotificationUtil.ts +29 -0
  43. package/Server/Utils/WhatsAppTemplateUtil.ts +6 -0
  44. package/Tests/UI/Components/Badge.test.tsx +5 -5
  45. package/Tests/UI/Components/Card.test.tsx +4 -8
  46. package/Tests/UI/Components/HiddenText.test.tsx +2 -5
  47. package/Tests/UI/Components/SideMenuItem.test.tsx +4 -2
  48. package/Types/AI/AIAgentTaskMetadata.ts +25 -0
  49. package/Types/AI/AIAgentTaskStatus.ts +65 -0
  50. package/Types/AI/AIAgentTaskType.ts +40 -0
  51. package/Types/Email/EmailTemplateType.ts +2 -0
  52. package/Types/Monitor/MonitorEvaluationSummary.ts +2 -1
  53. package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
  54. package/Types/Permission.ts +176 -0
  55. package/Types/WhatsApp/WhatsAppTemplates.ts +9 -0
  56. package/UI/Components/AIAgent/AIAgent.tsx +69 -0
  57. package/UI/Components/Badge/Badge.tsx +9 -5
  58. package/UI/Components/Banner/Banner.tsx +1 -1
  59. package/UI/Components/Card/Card.tsx +14 -12
  60. package/UI/Components/CodeBlock/CodeBlock.tsx +47 -4
  61. package/UI/Components/Detail/Detail.tsx +239 -49
  62. package/UI/Components/Detail/FieldLabel.tsx +35 -11
  63. package/UI/Components/Detail/PlaceholderText.tsx +18 -1
  64. package/UI/Components/Footer/Footer.tsx +9 -7
  65. package/UI/Components/Header/Header.tsx +4 -3
  66. package/UI/Components/Header/HeaderIconDropdownButton.tsx +13 -11
  67. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +3 -3
  68. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +1 -1
  69. package/UI/Components/Header/ProjectPicker/CreateNewProjectButton.tsx +4 -4
  70. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -6
  71. package/UI/Components/Header/ProjectPicker/ProjectPickerFilterBox.tsx +3 -3
  72. package/UI/Components/Header/ProjectPicker/ProjectPickerMenu.tsx +1 -1
  73. package/UI/Components/Header/ProjectPicker/ProjectPickerMenuItem.tsx +4 -4
  74. package/UI/Components/HeaderAlert/HeaderAlert.tsx +32 -32
  75. package/UI/Components/HeaderAlert/HeaderAlertGroup.tsx +1 -7
  76. package/UI/Components/HiddenText/HiddenText.tsx +98 -27
  77. package/UI/Components/Icon/Icon.tsx +12 -9
  78. package/UI/Components/InfoCard/InfoCard.tsx +7 -3
  79. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  80. package/UI/Components/ObjectID/ObjectIDView.tsx +73 -0
  81. package/UI/Components/Page/Page.tsx +3 -5
  82. package/UI/Components/SideMenu/SideMenu.tsx +175 -40
  83. package/UI/Components/SideMenu/SideMenuDivider.tsx +17 -0
  84. package/UI/Components/SideMenu/SideMenuItem.tsx +111 -158
  85. package/UI/Components/SideMenu/SideMenuSection.tsx +53 -3
  86. package/UI/Components/Table/Table.tsx +1 -1
  87. package/UI/Components/Types/FieldType.ts +2 -0
  88. package/UI/Config.ts +5 -0
  89. package/build/dist/Models/DatabaseModels/AIAgent.js +614 -0
  90. package/build/dist/Models/DatabaseModels/AIAgent.js.map +1 -0
  91. package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js +452 -0
  92. package/build/dist/Models/DatabaseModels/AIAgentOwnerTeam.js.map +1 -0
  93. package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js +451 -0
  94. package/build/dist/Models/DatabaseModels/AIAgentOwnerUser.js.map +1 -0
  95. package/build/dist/Models/DatabaseModels/AIAgentTask.js +580 -0
  96. package/build/dist/Models/DatabaseModels/AIAgentTask.js.map +1 -0
  97. package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js +438 -0
  98. package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js.map +1 -0
  99. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +771 -0
  100. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -0
  101. package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js +404 -0
  102. package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js.map +1 -0
  103. package/build/dist/Models/DatabaseModels/Index.js +14 -0
  104. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  105. package/build/dist/Models/DatabaseModels/Monitor.js +34 -0
  106. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  107. package/build/dist/Models/DatabaseModels/Project.js +26 -0
  108. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  109. package/build/dist/Models/DatabaseModels/TelemetryException.js +1 -1
  110. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  111. package/build/dist/Server/API/AIAgentAPI.js +141 -0
  112. package/build/dist/Server/API/AIAgentAPI.js.map +1 -0
  113. package/build/dist/Server/API/AIAgentDataAPI.js +415 -0
  114. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -0
  115. package/build/dist/Server/API/AIAgentTaskAPI.js +199 -0
  116. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -0
  117. package/build/dist/Server/API/AIAgentTaskLogAPI.js +106 -0
  118. package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -0
  119. package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js +9 -0
  120. package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js.map +1 -0
  121. package/build/dist/Server/API/GitHubAPI.js +23 -8
  122. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  123. package/build/dist/Server/API/TelemetryExceptionAPI.js +120 -0
  124. package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -0
  125. package/build/dist/Server/EnvironmentConfig.js +2 -0
  126. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  127. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766590916627-MigrationName.js +74 -0
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766590916627-MigrationName.js.map +1 -0
  129. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766600860972-MigrationName.js +18 -0
  130. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766600860972-MigrationName.js.map +1 -0
  131. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766606720183-MigrationName.js +12 -0
  132. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766606720183-MigrationName.js.map +1 -0
  133. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766688107858-MigrationName.js +28 -0
  134. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766688107858-MigrationName.js.map +1 -0
  135. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766754182870-MigrationName.js +32 -0
  136. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766754182870-MigrationName.js.map +1 -0
  137. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766774689743-MigrationName.js +60 -0
  138. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766774689743-MigrationName.js.map +1 -0
  139. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766777986427-MigrationName.js +18 -0
  140. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766777986427-MigrationName.js.map +1 -0
  141. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766918848434-AddAIAgentIsDefault.js +16 -0
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766918848434-AddAIAgentIsDefault.js.map +1 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766923324521-MigrationName.js +20 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766923324521-MigrationName.js.map +1 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766958924188-AddGitHubAppInstallationIdToProject.js +16 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1766958924188-AddGitHubAppInstallationIdToProject.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1767009661768-MigrationName.js +18 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1767009661768-MigrationName.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +22 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  151. package/build/dist/Server/Services/AIAgentOwnerTeamService.js +9 -0
  152. package/build/dist/Server/Services/AIAgentOwnerTeamService.js.map +1 -0
  153. package/build/dist/Server/Services/AIAgentOwnerUserService.js +9 -0
  154. package/build/dist/Server/Services/AIAgentOwnerUserService.js.map +1 -0
  155. package/build/dist/Server/Services/AIAgentService.js +471 -0
  156. package/build/dist/Server/Services/AIAgentService.js.map +1 -0
  157. package/build/dist/Server/Services/AIAgentTaskLogService.js +9 -0
  158. package/build/dist/Server/Services/AIAgentTaskLogService.js.map +1 -0
  159. package/build/dist/Server/Services/AIAgentTaskPullRequestService.js +9 -0
  160. package/build/dist/Server/Services/AIAgentTaskPullRequestService.js.map +1 -0
  161. package/build/dist/Server/Services/AIAgentTaskService.js +158 -0
  162. package/build/dist/Server/Services/AIAgentTaskService.js.map +1 -0
  163. package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js +36 -0
  164. package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js.map +1 -0
  165. package/build/dist/Server/Services/Index.js +10 -0
  166. package/build/dist/Server/Services/Index.js.map +1 -1
  167. package/build/dist/Server/Services/TelemetryExceptionService.js +137 -0
  168. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  169. package/build/dist/Server/Utils/Monitor/MonitorResource.js +168 -0
  170. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  171. package/build/dist/Server/Utils/PushNotificationUtil.js +21 -0
  172. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  173. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +4 -0
  174. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
  175. package/build/dist/Tests/UI/Components/Badge.test.js +5 -5
  176. package/build/dist/Tests/UI/Components/Badge.test.js.map +1 -1
  177. package/build/dist/Tests/UI/Components/Card.test.js +4 -8
  178. package/build/dist/Tests/UI/Components/Card.test.js.map +1 -1
  179. package/build/dist/Tests/UI/Components/HiddenText.test.js +2 -3
  180. package/build/dist/Tests/UI/Components/HiddenText.test.js.map +1 -1
  181. package/build/dist/Tests/UI/Components/SideMenuItem.test.js +3 -2
  182. package/build/dist/Tests/UI/Components/SideMenuItem.test.js.map +1 -1
  183. package/build/dist/Types/AI/AIAgentTaskMetadata.js +6 -0
  184. package/build/dist/Types/AI/AIAgentTaskMetadata.js.map +1 -0
  185. package/build/dist/Types/AI/AIAgentTaskStatus.js +51 -0
  186. package/build/dist/Types/AI/AIAgentTaskStatus.js.map +1 -0
  187. package/build/dist/Types/AI/AIAgentTaskType.js +29 -0
  188. package/build/dist/Types/AI/AIAgentTaskType.js.map +1 -0
  189. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  190. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  191. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
  192. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
  193. package/build/dist/Types/Permission.js +160 -0
  194. package/build/dist/Types/Permission.js.map +1 -1
  195. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js +6 -0
  196. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js.map +1 -1
  197. package/build/dist/UI/Components/AIAgent/AIAgent.js +32 -0
  198. package/build/dist/UI/Components/AIAgent/AIAgent.js.map +1 -0
  199. package/build/dist/UI/Components/Badge/Badge.js +9 -5
  200. package/build/dist/UI/Components/Badge/Badge.js.map +1 -1
  201. package/build/dist/UI/Components/Banner/Banner.js +1 -1
  202. package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
  203. package/build/dist/UI/Components/Card/Card.js +12 -12
  204. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  205. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +22 -2
  206. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  207. package/build/dist/UI/Components/Detail/Detail.js +117 -37
  208. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  209. package/build/dist/UI/Components/Detail/FieldLabel.js +12 -7
  210. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  211. package/build/dist/UI/Components/Detail/PlaceholderText.js +4 -1
  212. package/build/dist/UI/Components/Detail/PlaceholderText.js.map +1 -1
  213. package/build/dist/UI/Components/Footer/Footer.js +6 -6
  214. package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
  215. package/build/dist/UI/Components/Header/Header.js +4 -3
  216. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  217. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +7 -7
  218. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  219. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +3 -3
  220. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  221. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +1 -1
  222. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  223. package/build/dist/UI/Components/Header/ProjectPicker/CreateNewProjectButton.js +4 -4
  224. package/build/dist/UI/Components/Header/ProjectPicker/CreateNewProjectButton.js.map +1 -1
  225. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +6 -6
  226. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  227. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerFilterBox.js +2 -2
  228. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerFilterBox.js.map +1 -1
  229. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerMenu.js +1 -1
  230. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerMenu.js.map +1 -1
  231. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerMenuItem.js +4 -4
  232. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPickerMenuItem.js.map +1 -1
  233. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +31 -29
  234. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
  235. package/build/dist/UI/Components/HeaderAlert/HeaderAlertGroup.js +1 -3
  236. package/build/dist/UI/Components/HeaderAlert/HeaderAlertGroup.js.map +1 -1
  237. package/build/dist/UI/Components/HiddenText/HiddenText.js +33 -14
  238. package/build/dist/UI/Components/HiddenText/HiddenText.js.map +1 -1
  239. package/build/dist/UI/Components/Icon/Icon.js +3 -4
  240. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  241. package/build/dist/UI/Components/InfoCard/InfoCard.js +3 -3
  242. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  243. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  244. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  245. package/build/dist/UI/Components/ObjectID/ObjectIDView.js +30 -0
  246. package/build/dist/UI/Components/ObjectID/ObjectIDView.js.map +1 -0
  247. package/build/dist/UI/Components/Page/Page.js +3 -3
  248. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  249. package/build/dist/UI/Components/SideMenu/SideMenu.js +82 -17
  250. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  251. package/build/dist/UI/Components/SideMenu/SideMenuDivider.js +7 -0
  252. package/build/dist/UI/Components/SideMenu/SideMenuDivider.js.map +1 -0
  253. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +68 -97
  254. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  255. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +18 -3
  256. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  257. package/build/dist/UI/Components/Table/Table.js +1 -1
  258. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  259. package/build/dist/UI/Components/Types/FieldType.js +2 -0
  260. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  261. package/build/dist/UI/Config.js +2 -0
  262. package/build/dist/UI/Config.js.map +1 -1
  263. package/package.json +1 -1
@@ -0,0 +1,178 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/AIAgentTask";
3
+ import AIAgent from "../../Models/DatabaseModels/AIAgent";
4
+ import CreateBy from "../Types/Database/CreateBy";
5
+ import { OnCreate } from "../Types/Database/Hooks";
6
+ import BadDataException from "../../Types/Exception/BadDataException";
7
+ import AIAgentService from "./AIAgentService";
8
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
9
+ import ObjectID from "../../Types/ObjectID";
10
+ import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
11
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
12
+ import logger from "../Utils/Logger";
13
+ import OneUptimeDate from "../../Types/Date";
14
+
15
+ export class Service extends DatabaseService<Model> {
16
+ public constructor() {
17
+ super(Model);
18
+ }
19
+
20
+ @CaptureSpan()
21
+ protected override async onBeforeCreate(
22
+ createBy: CreateBy<Model>,
23
+ ): Promise<OnCreate<Model>> {
24
+ // If no aiAgentId is provided, assign one automatically
25
+ if (!createBy.data.aiAgentId) {
26
+ createBy.data.aiAgentId = await this.getDefaultAgentId(createBy);
27
+ } else {
28
+ // Validate the provided aiAgentId
29
+ await this.validateAgentBelongsToProject(createBy);
30
+ }
31
+
32
+ // Generate task number
33
+ if (!createBy.data.projectId) {
34
+ throw new BadDataException(
35
+ "Project ID is required to create an AI Agent Task",
36
+ );
37
+ }
38
+
39
+ const projectId: ObjectID = createBy.data.projectId;
40
+
41
+ let mutex: SemaphoreMutex | null = null;
42
+
43
+ try {
44
+ mutex = await Semaphore.lock({
45
+ key: projectId.toString(),
46
+ namespace: "AIAgentTaskService.task-create",
47
+ lockTimeout: 15000,
48
+ acquireTimeout: 20000,
49
+ });
50
+
51
+ logger.debug(
52
+ "Mutex acquired - AIAgentTaskService.task-create " +
53
+ projectId.toString() +
54
+ " at " +
55
+ OneUptimeDate.getCurrentDateAsFormattedString(),
56
+ );
57
+ } catch (err) {
58
+ logger.debug(
59
+ "Mutex acquire failed - AIAgentTaskService.task-create " +
60
+ projectId.toString() +
61
+ " at " +
62
+ OneUptimeDate.getCurrentDateAsFormattedString(),
63
+ );
64
+ logger.error(err);
65
+ }
66
+
67
+ try {
68
+ const taskNumberForThisTask: number =
69
+ (await this.getExistingTaskNumberForProject({
70
+ projectId: projectId,
71
+ })) + 1;
72
+
73
+ createBy.data.taskNumber = taskNumberForThisTask;
74
+ } finally {
75
+ if (mutex) {
76
+ await Semaphore.release(mutex);
77
+ }
78
+ }
79
+
80
+ return { createBy, carryForward: null };
81
+ }
82
+
83
+ @CaptureSpan()
84
+ public async getExistingTaskNumberForProject(data: {
85
+ projectId: ObjectID;
86
+ }): Promise<number> {
87
+ // get last task number.
88
+ const lastTask: Model | null = await this.findOneBy({
89
+ query: {
90
+ projectId: data.projectId,
91
+ },
92
+ select: {
93
+ taskNumber: true,
94
+ },
95
+ sort: {
96
+ createdAt: SortOrder.Descending,
97
+ },
98
+ props: {
99
+ isRoot: true,
100
+ },
101
+ });
102
+
103
+ if (!lastTask) {
104
+ return 0;
105
+ }
106
+
107
+ return lastTask.taskNumber ? Number(lastTask.taskNumber) : 0;
108
+ }
109
+
110
+ @CaptureSpan()
111
+ private async getDefaultAgentId(
112
+ createBy: CreateBy<Model>,
113
+ ): Promise<ObjectID> {
114
+ if (!createBy.data.projectId) {
115
+ throw new BadDataException(
116
+ "Project ID is required to assign an AI Agent",
117
+ );
118
+ }
119
+
120
+ // Try to get the default agent for the project (or global fallback)
121
+ const agent: AIAgent | null = await AIAgentService.getAIAgentForProject(
122
+ createBy.data.projectId,
123
+ );
124
+
125
+ if (!agent || !agent.id) {
126
+ throw new BadDataException(
127
+ "No AI Agent available. Please configure an AI Agent for this project or ensure a global AI Agent is available.",
128
+ );
129
+ }
130
+
131
+ return agent.id!;
132
+ }
133
+
134
+ @CaptureSpan()
135
+ private async validateAgentBelongsToProject(
136
+ createBy: CreateBy<Model>,
137
+ ): Promise<void> {
138
+ if (!createBy.data.aiAgentId || !createBy.data.projectId) {
139
+ return;
140
+ }
141
+
142
+ const agent: AIAgent | null = await AIAgentService.findOneById({
143
+ id: createBy.data.aiAgentId,
144
+ select: {
145
+ _id: true,
146
+ projectId: true,
147
+ isGlobalAIAgent: true,
148
+ },
149
+ props: {
150
+ isRoot: true,
151
+ },
152
+ });
153
+
154
+ if (!agent) {
155
+ throw new BadDataException("AI Agent not found");
156
+ }
157
+
158
+ // Allow if it's a global agent
159
+ if (agent.isGlobalAIAgent) {
160
+ return;
161
+ }
162
+
163
+ // Allow if the agent belongs to the same project
164
+ if (
165
+ agent.projectId &&
166
+ agent.projectId.toString() === createBy.data.projectId.toString()
167
+ ) {
168
+ return;
169
+ }
170
+
171
+ // Reject if the agent belongs to a different project
172
+ throw new BadDataException(
173
+ "The specified AI Agent does not belong to this project. Please use an AI Agent from your project or a global AI Agent.",
174
+ );
175
+ }
176
+ }
177
+
178
+ export default new Service();
@@ -0,0 +1,39 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/AIAgentTaskTelemetryException";
3
+ import ObjectID from "../../Types/ObjectID";
4
+ import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
5
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
6
+
7
+ export interface LinkTaskToTelemetryExceptionParams {
8
+ projectId: ObjectID;
9
+ aiAgentTaskId: ObjectID;
10
+ telemetryExceptionId: ObjectID;
11
+ props: DatabaseCommonInteractionProps;
12
+ }
13
+
14
+ export class Service extends DatabaseService<Model> {
15
+ public constructor() {
16
+ super(Model);
17
+ }
18
+
19
+ @CaptureSpan()
20
+ public async linkTaskToTelemetryException(
21
+ params: LinkTaskToTelemetryExceptionParams,
22
+ ): Promise<Model> {
23
+ const { projectId, aiAgentTaskId, telemetryExceptionId, props } = params;
24
+
25
+ const taskExceptionLink: Model = new Model();
26
+ taskExceptionLink.projectId = projectId;
27
+ taskExceptionLink.aiAgentTaskId = aiAgentTaskId;
28
+ taskExceptionLink.telemetryExceptionId = telemetryExceptionId;
29
+
30
+ return await this.create({
31
+ data: taskExceptionLink,
32
+ props: {
33
+ ...props,
34
+ },
35
+ });
36
+ }
37
+ }
38
+
39
+ export default new Service();
@@ -64,6 +64,11 @@ import OnCallDutyPolicyScheduleService from "./OnCallDutyPolicyScheduleService";
64
64
  // On-Call Duty
65
65
  import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
66
66
  import ProbeService from "./ProbeService";
67
+ import AIAgentService from "./AIAgentService";
68
+ import AIAgentOwnerUserService from "./AIAgentOwnerUserService";
69
+ import AIAgentOwnerTeamService from "./AIAgentOwnerTeamService";
70
+ import AIAgentTaskLogService from "./AIAgentTaskLogService";
71
+ import AIAgentTaskPullRequestService from "./AIAgentTaskPullRequestService";
67
72
  import ProjectCallSMSConfigService from "./ProjectCallSMSConfigService";
68
73
  import ProjectService from "./ProjectService";
69
74
  // Project SMTP Config.
@@ -241,6 +246,11 @@ const services: Array<BaseService> = [
241
246
  ProjectService,
242
247
  ProjectSmtpConfigService,
243
248
  ProbeService,
249
+ AIAgentService,
250
+ AIAgentOwnerUserService,
251
+ AIAgentOwnerTeamService,
252
+ AIAgentTaskLogService,
253
+ AIAgentTaskPullRequestService,
244
254
  ProjectSsoService,
245
255
 
246
256
  ScheduledMaintenanceCustomFieldService,
@@ -1,10 +1,172 @@
1
1
  import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/TelemetryException";
3
+ import AIAgentTask from "../../Models/DatabaseModels/AIAgentTask";
4
+ import AIAgentTaskTelemetryException from "../../Models/DatabaseModels/AIAgentTaskTelemetryException";
5
+ import ObjectID from "../../Types/ObjectID";
6
+ import BadDataException from "../../Types/Exception/BadDataException";
7
+ import AIAgentTaskType from "../../Types/AI/AIAgentTaskType";
8
+ import AIAgentTaskStatus from "../../Types/AI/AIAgentTaskStatus";
9
+ import { FixExceptionTaskMetadata } from "../../Types/AI/AIAgentTaskMetadata";
10
+ import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
11
+ import AIAgentTaskService from "./AIAgentTaskService";
12
+ import AIAgentTaskTelemetryExceptionService from "./AIAgentTaskTelemetryExceptionService";
13
+ import QueryHelper from "../Types/Database/QueryHelper";
14
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
15
+
16
+ export interface CreateAIAgentTaskForExceptionParams {
17
+ telemetryExceptionId: ObjectID;
18
+ props: DatabaseCommonInteractionProps;
19
+ }
3
20
 
4
21
  export class Service extends DatabaseService<Model> {
5
22
  public constructor() {
6
23
  super(Model);
7
24
  }
25
+
26
+ @CaptureSpan()
27
+ public async createAIAgentTaskForException(
28
+ params: CreateAIAgentTaskForExceptionParams,
29
+ ): Promise<AIAgentTask> {
30
+ const { telemetryExceptionId, props } = params;
31
+
32
+ // Get the telemetry exception
33
+ const telemetryException: Model | null = await this.findOneById({
34
+ id: telemetryExceptionId,
35
+ select: {
36
+ _id: true,
37
+ projectId: true,
38
+ message: true,
39
+ stackTrace: true,
40
+ telemetryServiceId: true,
41
+ exceptionType: true,
42
+ },
43
+ props,
44
+ });
45
+
46
+ if (!telemetryException || !telemetryException.projectId) {
47
+ throw new BadDataException("Telemetry Exception not found");
48
+ }
49
+
50
+ // Check if an active AI agent task already exists for this exception
51
+ await this.validateNoActiveTaskExists(telemetryExceptionId);
52
+
53
+ // Create the AI Agent Task
54
+ const createdTask: AIAgentTask = await this.createFixExceptionTask({
55
+ telemetryException,
56
+ telemetryExceptionId,
57
+ props,
58
+ });
59
+
60
+ // Link the task to the telemetry exception
61
+ await AIAgentTaskTelemetryExceptionService.linkTaskToTelemetryException({
62
+ projectId: telemetryException.projectId,
63
+ aiAgentTaskId: createdTask.id!,
64
+ telemetryExceptionId,
65
+ props,
66
+ });
67
+
68
+ return createdTask;
69
+ }
70
+
71
+ @CaptureSpan()
72
+ private async validateNoActiveTaskExists(
73
+ telemetryExceptionId: ObjectID,
74
+ ): Promise<void> {
75
+ const existingTaskLink: AIAgentTaskTelemetryException | null =
76
+ await AIAgentTaskTelemetryExceptionService.findOneBy({
77
+ query: {
78
+ telemetryExceptionId: telemetryExceptionId,
79
+ aiAgentTask: {
80
+ status: QueryHelper.notIn([
81
+ AIAgentTaskStatus.Completed,
82
+ AIAgentTaskStatus.Error,
83
+ ]),
84
+ },
85
+ },
86
+ select: {
87
+ _id: true,
88
+ aiAgentTaskId: true,
89
+ },
90
+ props: {
91
+ isRoot: true,
92
+ },
93
+ });
94
+
95
+ if (existingTaskLink) {
96
+ throw new BadDataException(
97
+ "An AI agent task is already in progress for this exception. Please wait for it to complete before creating a new one.",
98
+ );
99
+ }
100
+ }
101
+
102
+ @CaptureSpan()
103
+ private async createFixExceptionTask(params: {
104
+ telemetryException: Model;
105
+ telemetryExceptionId: ObjectID;
106
+ props: DatabaseCommonInteractionProps;
107
+ }): Promise<AIAgentTask> {
108
+ const { telemetryException, telemetryExceptionId, props } = params;
109
+
110
+ const aiAgentTask: AIAgentTask = new AIAgentTask();
111
+ aiAgentTask.projectId = telemetryException.projectId!;
112
+ aiAgentTask.taskType = AIAgentTaskType.FixException;
113
+ aiAgentTask.status = AIAgentTaskStatus.Scheduled;
114
+
115
+ // Set name and description based on exception details
116
+ const exceptionType: string =
117
+ telemetryException.exceptionType || "Exception";
118
+ const exceptionMessage: string =
119
+ telemetryException.message || "No message available";
120
+
121
+ aiAgentTask.name = `Fix ${exceptionType}: ${exceptionMessage}`;
122
+ aiAgentTask.description = `AI Agent task to fix the exception: ${exceptionMessage}`;
123
+
124
+ // Build metadata
125
+ aiAgentTask.metadata = this.buildFixExceptionMetadata({
126
+ telemetryException,
127
+ telemetryExceptionId,
128
+ });
129
+
130
+ const createdTask: AIAgentTask = await AIAgentTaskService.create({
131
+ data: aiAgentTask,
132
+ props: {
133
+ ...props,
134
+ },
135
+ });
136
+
137
+ if (!createdTask.id) {
138
+ throw new BadDataException("Failed to create AI Agent Task");
139
+ }
140
+
141
+ return createdTask;
142
+ }
143
+
144
+ private buildFixExceptionMetadata(params: {
145
+ telemetryException: Model;
146
+ telemetryExceptionId: ObjectID;
147
+ }): FixExceptionTaskMetadata {
148
+ const { telemetryException, telemetryExceptionId } = params;
149
+
150
+ const metadata: FixExceptionTaskMetadata = {
151
+ taskType: AIAgentTaskType.FixException,
152
+ exceptionId: telemetryExceptionId.toString(),
153
+ };
154
+
155
+ if (telemetryException.stackTrace) {
156
+ metadata.stackTrace = telemetryException.stackTrace;
157
+ }
158
+
159
+ if (telemetryException.message) {
160
+ metadata.errorMessage = telemetryException.message;
161
+ }
162
+
163
+ if (telemetryException.telemetryServiceId) {
164
+ metadata.telemetryServiceId =
165
+ telemetryException.telemetryServiceId.toString();
166
+ }
167
+
168
+ return metadata;
169
+ }
8
170
  }
9
171
 
10
172
  export default new Service();
@@ -40,6 +40,17 @@ import CaptureSpan from "../Telemetry/CaptureSpan";
40
40
  import ExceptionMessages from "../../../Types/Exception/ExceptionMessages";
41
41
  import MonitorEvaluationSummary from "../../../Types/Monitor/MonitorEvaluationSummary";
42
42
  import MonitorStatusService from "../../Services/MonitorStatusService";
43
+ import { ProbeConnectionStatus } from "../../../Models/DatabaseModels/Probe";
44
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
45
+
46
+ interface ProbeAgreementResult {
47
+ hasAgreement: boolean;
48
+ agreementCount: number;
49
+ requiredCount: number;
50
+ totalActiveProbes: number;
51
+ agreedCriteriaId: string | null;
52
+ agreedRootCause: string | null;
53
+ }
43
54
 
44
55
  export default class MonitorResourceUtil {
45
56
  @CaptureSpan()
@@ -125,6 +136,7 @@ export default class MonitorResourceUtil {
125
136
  currentMonitorStatusId: true,
126
137
  _id: true,
127
138
  name: true,
139
+ minimumProbeAgreement: true,
128
140
  },
129
141
  props: {
130
142
  isRoot: true,
@@ -500,6 +512,62 @@ export default class MonitorResourceUtil {
500
512
  evaluationSummary: evaluationSummary,
501
513
  });
502
514
 
515
+ // Check probe agreement for probe-based monitors
516
+ if (
517
+ monitor.monitorType &&
518
+ MonitorTypeHelper.isProbableMonitor(monitor.monitorType)
519
+ ) {
520
+ const probeAgreementResult: ProbeAgreementResult =
521
+ await MonitorResourceUtil.checkProbeAgreement({
522
+ monitor: monitor,
523
+ monitorStep: monitorStep,
524
+ currentCriteriaMetId: response.criteriaMetId || null,
525
+ currentRootCause: response.rootCause || null,
526
+ });
527
+
528
+ // Add probe agreement event to evaluation summary
529
+ evaluationSummary.events.push({
530
+ type: "probe-agreement",
531
+ title: "Probe Agreement Check",
532
+ message: probeAgreementResult.hasAgreement
533
+ ? `Probe agreement reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total).`
534
+ : `Probe agreement not reached: ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree (${probeAgreementResult.totalActiveProbes} active probes total). Skipping status change.`,
535
+ at: OneUptimeDate.getCurrentDate(),
536
+ });
537
+
538
+ if (!probeAgreementResult.hasAgreement) {
539
+ logger.debug(
540
+ `${dataToProcess.monitorId.toString()} - Probe agreement not met. ${probeAgreementResult.agreementCount}/${probeAgreementResult.requiredCount} probes agree. Skipping status change.`,
541
+ );
542
+
543
+ // Release lock and return early - no status change
544
+ if (mutex) {
545
+ try {
546
+ await Semaphore.release(mutex);
547
+ } catch (err) {
548
+ logger.error(err);
549
+ }
550
+ }
551
+
552
+ await persistLatestMonitorPayload();
553
+
554
+ MonitorLogUtil.saveMonitorLog({
555
+ monitorId: monitor.id!,
556
+ projectId: monitor.projectId!,
557
+ dataToProcess: dataToProcess,
558
+ });
559
+
560
+ response.evaluationSummary = evaluationSummary;
561
+ return response;
562
+ }
563
+
564
+ // Use the agreed criteria result
565
+ response.criteriaMetId = probeAgreementResult.agreedCriteriaId
566
+ ? probeAgreementResult.agreedCriteriaId
567
+ : undefined;
568
+ response.rootCause = probeAgreementResult.agreedRootCause;
569
+ }
570
+
503
571
  if (response.criteriaMetId && response.rootCause) {
504
572
  logger.debug(
505
573
  `${dataToProcess.monitorId.toString()} - Criteria met: ${
@@ -735,4 +803,164 @@ export default class MonitorResourceUtil {
735
803
 
736
804
  return response;
737
805
  }
806
+
807
+ @CaptureSpan()
808
+ private static async checkProbeAgreement(input: {
809
+ monitor: Monitor;
810
+ monitorStep: MonitorStep;
811
+ currentCriteriaMetId: string | null;
812
+ currentRootCause: string | null;
813
+ }): Promise<ProbeAgreementResult> {
814
+ const { monitor, monitorStep, currentCriteriaMetId, currentRootCause } =
815
+ input;
816
+
817
+ /*
818
+ * If minimumProbeAgreement is not set, all probes must agree
819
+ * Get all MonitorProbes for this monitor with their probe connection status
820
+ */
821
+ const monitorProbes: Array<MonitorProbe> = await MonitorProbeService.findBy(
822
+ {
823
+ query: {
824
+ monitorId: monitor.id!,
825
+ },
826
+ select: {
827
+ probeId: true,
828
+ isEnabled: true,
829
+ lastMonitoringLog: true,
830
+ probe: {
831
+ connectionStatus: true,
832
+ },
833
+ },
834
+ limit: LIMIT_PER_PROJECT,
835
+ skip: 0,
836
+ props: {
837
+ isRoot: true,
838
+ },
839
+ },
840
+ );
841
+
842
+ // Filter to only active probes (enabled AND connected)
843
+ const activeProbes: Array<MonitorProbe> = monitorProbes.filter(
844
+ (mp: MonitorProbe) => {
845
+ return (
846
+ mp.isEnabled &&
847
+ mp.probe?.connectionStatus === ProbeConnectionStatus.Connected
848
+ );
849
+ },
850
+ );
851
+
852
+ // If no active probes, treat as agreement met (nothing to compare)
853
+ if (activeProbes.length === 0) {
854
+ logger.debug(
855
+ `${monitor.id?.toString()} - No active probes found. Treating as agreement met.`,
856
+ );
857
+ return {
858
+ hasAgreement: true,
859
+ agreementCount: 0,
860
+ requiredCount: 0,
861
+ totalActiveProbes: 0,
862
+ agreedCriteriaId: currentCriteriaMetId,
863
+ agreedRootCause: currentRootCause,
864
+ };
865
+ }
866
+
867
+ // Determine required count for agreement
868
+ const requiredCount: number =
869
+ monitor.minimumProbeAgreement ?? activeProbes.length;
870
+ // Effective threshold cannot exceed number of active probes
871
+ const effectiveThreshold: number = Math.min(
872
+ requiredCount,
873
+ activeProbes.length,
874
+ );
875
+
876
+ /*
877
+ * Count how many probes agree on each criteria result
878
+ * Key: criteriaId or "none" for no criteria met
879
+ * Value: { count, rootCause }
880
+ */
881
+ const criteriaAgreements: Map<
882
+ string,
883
+ { count: number; rootCause: string | null }
884
+ > = new Map();
885
+
886
+ const stepId: string = monitorStep.id.toString();
887
+
888
+ for (const monitorProbe of activeProbes) {
889
+ const probeResponse: ProbeMonitorResponse | undefined =
890
+ monitorProbe.lastMonitoringLog?.[stepId];
891
+
892
+ if (!probeResponse) {
893
+ // No response yet for this step from this probe - skip
894
+ logger.debug(
895
+ `${monitor.id?.toString()} - Probe ${monitorProbe.probeId?.toString()} has no response for step ${stepId}. Skipping.`,
896
+ );
897
+ continue;
898
+ }
899
+
900
+ // Evaluate this probe's response against criteria
901
+ const tempResponse: ProbeApiIngestResponse = {
902
+ monitorId: monitor.id!,
903
+ criteriaMetId: undefined,
904
+ rootCause: null,
905
+ };
906
+
907
+ const tempEvaluationSummary: MonitorEvaluationSummary = {
908
+ evaluatedAt: OneUptimeDate.getCurrentDate(),
909
+ criteriaResults: [],
910
+ events: [],
911
+ };
912
+
913
+ const evaluatedResponse: ProbeApiIngestResponse =
914
+ await MonitorCriteriaEvaluator.processMonitorStep({
915
+ dataToProcess: probeResponse as DataToProcess,
916
+ monitorStep: monitorStep,
917
+ monitor: monitor,
918
+ probeApiIngestResponse: tempResponse,
919
+ evaluationSummary: tempEvaluationSummary,
920
+ });
921
+
922
+ // Record the result
923
+ const criteriaKey: string = evaluatedResponse.criteriaMetId || "none";
924
+ const existing: { count: number; rootCause: string | null } | undefined =
925
+ criteriaAgreements.get(criteriaKey);
926
+
927
+ if (existing) {
928
+ existing.count += 1;
929
+ } else {
930
+ criteriaAgreements.set(criteriaKey, {
931
+ count: 1,
932
+ rootCause: evaluatedResponse.rootCause,
933
+ });
934
+ }
935
+ }
936
+
937
+ // Find the criteria with the most agreement
938
+ let maxCount: number = 0;
939
+ let winningCriteriaId: string | null = null;
940
+ let winningRootCause: string | null = null;
941
+
942
+ for (const [criteriaId, data] of criteriaAgreements) {
943
+ if (data.count > maxCount) {
944
+ maxCount = data.count;
945
+ winningCriteriaId = criteriaId === "none" ? null : criteriaId;
946
+ winningRootCause = data.rootCause;
947
+ }
948
+ }
949
+
950
+ // Check if the winning criteria has reached the agreement threshold
951
+ const hasAgreement: boolean = maxCount >= effectiveThreshold;
952
+
953
+ logger.debug(
954
+ `${monitor.id?.toString()} - Probe agreement check: ${maxCount}/${effectiveThreshold} probes agree on criteria "${winningCriteriaId || "none"}". Agreement ${hasAgreement ? "reached" : "not reached"}.`,
955
+ );
956
+
957
+ return {
958
+ hasAgreement,
959
+ agreementCount: maxCount,
960
+ requiredCount: effectiveThreshold,
961
+ totalActiveProbes: activeProbes.length,
962
+ agreedCriteriaId: hasAgreement ? winningCriteriaId : null,
963
+ agreedRootCause: hasAgreement ? winningRootCause : null,
964
+ };
965
+ }
738
966
  }
@@ -327,4 +327,33 @@ export default class PushNotificationUtil {
327
327
 
328
328
  return PushNotificationUtil.applyDefaults(notification);
329
329
  }
330
+
331
+ public static createAIAgentStatusChangedNotification(params: {
332
+ aiAgentName: string;
333
+ projectName: string;
334
+ connectionStatus: string;
335
+ clickAction?: string;
336
+ }): PushNotificationMessage {
337
+ const { aiAgentName, projectName, connectionStatus, clickAction } = params;
338
+ const notification: Partial<PushNotificationMessage> = {
339
+ title: `AI Agent ${connectionStatus}: ${aiAgentName}`,
340
+ body: `AI Agent ${aiAgentName} is ${connectionStatus} in ${projectName}. Click to view details.`,
341
+ tag: "ai-agent-status-changed",
342
+ requireInteraction: true,
343
+ data: {
344
+ type: "ai-agent-status-changed",
345
+ aiAgentName: aiAgentName,
346
+ projectName: projectName,
347
+ connectionStatus: connectionStatus,
348
+ },
349
+ };
350
+
351
+ if (clickAction) {
352
+ notification.clickAction = clickAction;
353
+ notification.url = clickAction;
354
+ notification.data!["url"] = clickAction;
355
+ }
356
+
357
+ return PushNotificationUtil.applyDefaults(notification);
358
+ }
330
359
  }