@oneuptime/common 11.3.25 → 11.3.28

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 (397) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +322 -0
  2. package/Models/DatabaseModels/AIConversationMessage.ts +495 -0
  3. package/Models/DatabaseModels/AIRun.ts +584 -0
  4. package/Models/DatabaseModels/AIRunEvent.ts +443 -0
  5. package/Models/DatabaseModels/IncidentEpisodeRoleMember.ts +1 -1
  6. package/Models/DatabaseModels/IncidentMember.ts +1 -1
  7. package/Models/DatabaseModels/IncomingCallPolicy.ts +13 -0
  8. package/Models/DatabaseModels/Index.ts +11 -0
  9. package/Models/DatabaseModels/LlmLog.ts +26 -0
  10. package/Models/DatabaseModels/LlmProvider.ts +2 -2
  11. package/Models/DatabaseModels/MigrationFailure.ts +170 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +51 -2
  13. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +44 -0
  14. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +6 -0
  15. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.ts +6 -0
  16. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +1 -1
  17. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +2 -2
  18. package/Server/API/AIChatAPI.ts +693 -0
  19. package/Server/API/AlertAPI.ts +1 -1
  20. package/Server/API/IncidentAPI.ts +2 -2
  21. package/Server/API/IncidentEpisodeAPI.ts +1 -1
  22. package/Server/API/LlmProviderAPI.ts +170 -0
  23. package/Server/API/MicrosoftTeamsAPI.ts +5 -0
  24. package/Server/API/ScheduledMaintenanceAPI.ts +1 -1
  25. package/Server/API/SlackAPI.ts +663 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.ts +245 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.ts +36 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.ts +46 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.ts +119 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.ts +25 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.ts +81 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.ts +25 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.ts +35 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  35. package/Server/Infrastructure/PostgresDatabase.ts +11 -0
  36. package/Server/Services/AIConversationMessageService.ts +39 -0
  37. package/Server/Services/AIConversationService.ts +63 -0
  38. package/Server/Services/AIRunEventService.ts +39 -0
  39. package/Server/Services/AIRunService.ts +39 -0
  40. package/Server/Services/AIService.ts +127 -33
  41. package/Server/Services/AnalyticsDatabaseService.ts +10 -1
  42. package/Server/Services/DatabaseService.ts +29 -1
  43. package/Server/Services/IncidentService.ts +1 -1
  44. package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +75 -2
  45. package/Server/Services/IncomingCallPolicyService.ts +42 -1
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/LlmProviderService.ts +110 -0
  48. package/Server/Services/MigrationFailureService.ts +9 -0
  49. package/Server/Services/MonitorProbeService.ts +33 -7
  50. package/Server/Services/MonitorService.ts +19 -7
  51. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  52. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +185 -41
  53. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +23 -15
  54. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +39 -0
  55. package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +148 -0
  56. package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +11 -2
  57. package/Server/Services/OnCallDutyPolicyScheduleService.ts +502 -26
  58. package/Server/Services/OnCallDutyPolicyTimeLogService.ts +49 -7
  59. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +218 -4
  60. package/Server/Services/ProjectCallSMSConfigService.ts +82 -1
  61. package/Server/Services/ProjectService.ts +24 -0
  62. package/Server/Services/TeamMemberService.ts +6 -0
  63. package/Server/Services/UserNotificationRuleService.ts +13 -42
  64. package/Server/Services/UserOnCallLogService.ts +90 -0
  65. package/Server/Services/UserOnCallLogTimelineService.ts +43 -1
  66. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +74 -9
  67. package/Server/Types/Database/QueryUtil.ts +57 -0
  68. package/Server/Utils/AI/AIChatPrivacyFilter.ts +28 -0
  69. package/Server/Utils/AI/AlertAIContextBuilder.ts +6 -1
  70. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +1066 -0
  71. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +239 -0
  72. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +51 -0
  73. package/Server/Utils/AI/IncidentAIContextBuilder.ts +18 -3
  74. package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +6 -1
  75. package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +12 -2
  76. package/Server/Utils/AI/Toolbox/AlertTools.ts +201 -0
  77. package/Server/Utils/AI/Toolbox/AlertWriteTools.ts +174 -0
  78. package/Server/Utils/AI/Toolbox/ContextTools.ts +189 -0
  79. package/Server/Utils/AI/Toolbox/ExceptionTools.ts +149 -0
  80. package/Server/Utils/AI/Toolbox/IncidentTools.ts +386 -0
  81. package/Server/Utils/AI/Toolbox/IncidentWriteTools.ts +350 -0
  82. package/Server/Utils/AI/Toolbox/Index.ts +231 -0
  83. package/Server/Utils/AI/Toolbox/LogTools.ts +339 -0
  84. package/Server/Utils/AI/Toolbox/MetricTools.ts +179 -0
  85. package/Server/Utils/AI/Toolbox/MonitorTools.ts +193 -0
  86. package/Server/Utils/AI/Toolbox/RecentChangesTools.ts +208 -0
  87. package/Server/Utils/AI/Toolbox/Serializer.ts +299 -0
  88. package/Server/Utils/AI/Toolbox/ToolTypes.ts +249 -0
  89. package/Server/Utils/AI/Toolbox/TraceTools.ts +402 -0
  90. package/Server/Utils/AI/Toolbox/WidgetBuilder.ts +189 -0
  91. package/Server/Utils/Database/MigrationFailureLog.ts +240 -0
  92. package/Server/Utils/IncomingCallPhoneNumber.ts +41 -0
  93. package/Server/Utils/LLM/LLMService.ts +605 -96
  94. package/Server/Utils/Telemetry/IoTSnapshotScan.ts +12 -9
  95. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +12 -9
  96. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +512 -19
  97. package/Server/Utils/Workspace/Slack/Slack.ts +80 -0
  98. package/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  99. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +0 -8
  100. package/Tests/Server/Services/OnCallDutyPolicyScheduleLayerUserReorder.test.ts +233 -0
  101. package/Tests/Server/Services/OnCallDutyPolicyTimeLogServiceScoping.test.ts +242 -0
  102. package/Tests/Server/Services/OnCallDutyPolicyUserOverrideEdit.test.ts +198 -0
  103. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +495 -0
  104. package/Tests/Server/Types/Database/QueryUtil.test.ts +74 -0
  105. package/Tests/Server/Utils/AI/AIChatModelACL.test.ts +42 -0
  106. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +89 -0
  107. package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +139 -0
  108. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +386 -0
  109. package/Tests/Server/Utils/AI/ToolArgsGetTimeRange.test.ts +62 -0
  110. package/Tests/Server/Utils/AI/ToolArgsScopeServiceIds.test.ts +79 -0
  111. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +223 -0
  112. package/Tests/Types/Billing/SubscriptionStatus.test.ts +127 -0
  113. package/Tests/Types/DateExhaustiveTimezone.test.ts +700 -0
  114. package/Tests/Types/DateTimezoneWallClock.test.ts +99 -0
  115. package/Tests/Types/Events/Recurring.test.ts +22 -9
  116. package/Tests/Types/Metrics/RecordingRuleDefinition.test.ts +213 -0
  117. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixes.test.ts +291 -0
  118. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixesRound2.test.ts +398 -0
  119. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeekendGap.test.ts +114 -0
  120. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeeklyDayShift.test.ts +76 -0
  121. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyMutation.test.ts +128 -0
  122. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyProbe.test.ts +203 -0
  123. package/Tests/Types/OnCallDutyPolicy/LayerUtilDiffFuzz.test.ts +322 -0
  124. package/Tests/Types/OnCallDutyPolicy/LayerUtilEdgeCases.test.ts +280 -0
  125. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveCurrentUser.test.ts +863 -0
  126. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveDaily.test.ts +900 -0
  127. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveMultiLayer.test.ts +1104 -0
  128. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +957 -0
  129. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveWeekly.test.ts +1095 -0
  130. package/Tests/Types/OnCallDutyPolicy/LayerUtilInvariants.test.ts +232 -0
  131. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +227 -0
  132. package/Tests/Types/OnCallDutyPolicy/LayerUtilMonthYearAudit.test.ts +255 -0
  133. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerAudit.test.ts +388 -0
  134. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerEdge.test.ts +300 -0
  135. package/Tests/Types/OnCallDutyPolicy/LayerUtilOvernightDSTAudit.test.ts +158 -0
  136. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapFix.test.ts +253 -0
  137. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapRepro.test.ts +157 -0
  138. package/Tests/Types/OnCallDutyPolicy/LayerUtilRotationFixes.test.ts +414 -0
  139. package/Tests/Types/OnCallDutyPolicy/LayerUtilTimezone.test.ts +243 -0
  140. package/Tests/Types/OnCallDutyPolicy/LayerUtilWeekendGapRepro.test.ts +112 -0
  141. package/Tests/Types/OnCallDutyPolicy/OverrideLensAudit.test.ts +117 -0
  142. package/Tests/Types/OnCallDutyPolicy/RestrictionTimes.test.ts +8 -6
  143. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesDefaultDayAudit.test.ts +112 -0
  144. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesExhaustive.test.ts +821 -0
  145. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesMutationInvariant.test.ts +886 -0
  146. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtil.test.ts +255 -0
  147. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtilExhaustive.test.ts +1126 -0
  148. package/Types/AI/AIChatMessageRole.ts +6 -0
  149. package/Types/AI/AIChatMessageStatus.ts +32 -0
  150. package/Types/AI/AIChatPermissionMode.ts +69 -0
  151. package/Types/AI/AIChatTypes.ts +231 -0
  152. package/Types/AI/AIRunEventType.ts +17 -0
  153. package/Types/AI/AIRunStatus.ts +28 -0
  154. package/Types/AI/AIRunType.ts +6 -0
  155. package/Types/Date.ts +200 -15
  156. package/Types/LLM/LlmType.ts +6 -0
  157. package/Types/OnCallDutyPolicy/Layer.ts +790 -260
  158. package/Types/OnCallDutyPolicy/RestrictionTimes.ts +39 -13
  159. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +21 -5
  160. package/UI/Components/Events/RecurringFieldElement.tsx +16 -0
  161. package/UI/Components/Header/HeaderIconDropdownButton.tsx +22 -12
  162. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +35 -3
  163. package/UI/Components/ModelFormModal/ModelFormModal.tsx +8 -0
  164. package/UI/Components/Page/Page.tsx +14 -0
  165. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +1 -1
  166. package/UI/Utils/LlmTypeDropdownOptions.ts +40 -0
  167. package/UI/Utils/TestLLMProvider.ts +59 -0
  168. package/build/dist/Models/DatabaseModels/AIConversation.js +345 -0
  169. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -0
  170. package/build/dist/Models/DatabaseModels/AIConversationMessage.js +521 -0
  171. package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -0
  172. package/build/dist/Models/DatabaseModels/AIRun.js +619 -0
  173. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -0
  174. package/build/dist/Models/DatabaseModels/AIRunEvent.js +469 -0
  175. package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -0
  176. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js +1 -1
  177. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/IncidentMember.js +1 -1
  179. package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +10 -0
  181. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  183. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/LlmLog.js +28 -0
  185. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/LlmProvider.js +2 -2
  187. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/MigrationFailure.js +196 -0
  189. package/build/dist/Models/DatabaseModels/MigrationFailure.js.map +1 -0
  190. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +52 -2
  191. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +45 -0
  193. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +6 -0
  195. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js +6 -0
  197. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +1 -1
  199. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +2 -2
  201. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  202. package/build/dist/Server/API/AIChatAPI.js +498 -0
  203. package/build/dist/Server/API/AIChatAPI.js.map +1 -0
  204. package/build/dist/Server/API/AlertAPI.js +1 -1
  205. package/build/dist/Server/API/IncidentAPI.js +2 -2
  206. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  207. package/build/dist/Server/API/LlmProviderAPI.js +108 -1
  208. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  209. package/build/dist/Server/API/MicrosoftTeamsAPI.js +4 -0
  210. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  211. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  212. package/build/dist/Server/API/SlackAPI.js +442 -0
  213. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  214. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js +96 -0
  215. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js.map +1 -0
  216. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js +25 -0
  217. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js.map +1 -0
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js +31 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js +46 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js +18 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js.map +1 -0
  224. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js +38 -0
  225. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js.map +1 -0
  226. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js +16 -0
  227. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js.map +1 -0
  228. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js +18 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js.map +1 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  232. package/build/dist/Server/Infrastructure/PostgresDatabase.js +9 -0
  233. package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
  234. package/build/dist/Server/Services/AIConversationMessageService.js +34 -0
  235. package/build/dist/Server/Services/AIConversationMessageService.js.map +1 -0
  236. package/build/dist/Server/Services/AIConversationService.js +42 -0
  237. package/build/dist/Server/Services/AIConversationService.js.map +1 -0
  238. package/build/dist/Server/Services/AIRunEventService.js +34 -0
  239. package/build/dist/Server/Services/AIRunEventService.js.map +1 -0
  240. package/build/dist/Server/Services/AIRunService.js +34 -0
  241. package/build/dist/Server/Services/AIRunService.js.map +1 -0
  242. package/build/dist/Server/Services/AIService.js +84 -25
  243. package/build/dist/Server/Services/AIService.js.map +1 -1
  244. package/build/dist/Server/Services/AnalyticsDatabaseService.js +10 -1
  245. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  246. package/build/dist/Server/Services/DatabaseService.js +20 -1
  247. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  248. package/build/dist/Server/Services/IncidentService.js +1 -1
  249. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +55 -2
  250. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -1
  251. package/build/dist/Server/Services/IncomingCallPolicyService.js +40 -0
  252. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -1
  253. package/build/dist/Server/Services/Index.js +2 -0
  254. package/build/dist/Server/Services/Index.js.map +1 -1
  255. package/build/dist/Server/Services/LlmProviderService.js +108 -0
  256. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  257. package/build/dist/Server/Services/MigrationFailureService.js +9 -0
  258. package/build/dist/Server/Services/MigrationFailureService.js.map +1 -0
  259. package/build/dist/Server/Services/MonitorProbeService.js +33 -7
  260. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  261. package/build/dist/Server/Services/MonitorService.js +12 -5
  262. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  263. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +81 -22
  264. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  265. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +134 -31
  266. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  267. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +21 -13
  268. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  269. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +36 -0
  270. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  271. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +121 -0
  272. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
  273. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +11 -2
  274. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
  275. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +409 -36
  276. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  277. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +52 -8
  278. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -1
  279. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +170 -3
  280. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  281. package/build/dist/Server/Services/ProjectCallSMSConfigService.js +72 -0
  282. package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
  283. package/build/dist/Server/Services/ProjectService.js +25 -0
  284. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  285. package/build/dist/Server/Services/TeamMemberService.js +6 -0
  286. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  287. package/build/dist/Server/Services/UserNotificationRuleService.js +12 -30
  288. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  289. package/build/dist/Server/Services/UserOnCallLogService.js +75 -0
  290. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  291. package/build/dist/Server/Services/UserOnCallLogTimelineService.js +31 -1
  292. package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
  293. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +50 -7
  294. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  295. package/build/dist/Server/Types/Database/QueryUtil.js +45 -0
  296. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  297. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +18 -0
  298. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -0
  299. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +6 -1
  300. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
  301. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +756 -0
  302. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -0
  303. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +165 -0
  304. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -0
  305. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +44 -0
  306. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -0
  307. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +18 -3
  308. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +6 -1
  310. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
  311. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +12 -2
  312. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -1
  313. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +167 -0
  314. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -0
  315. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js +136 -0
  316. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js.map +1 -0
  317. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js +141 -0
  318. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js.map +1 -0
  319. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js +117 -0
  320. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js.map +1 -0
  321. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +318 -0
  322. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -0
  323. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js +280 -0
  324. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js.map +1 -0
  325. package/build/dist/Server/Utils/AI/Toolbox/Index.js +153 -0
  326. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -0
  327. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js +246 -0
  328. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js.map +1 -0
  329. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +120 -0
  330. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -0
  331. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +158 -0
  332. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -0
  333. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js +165 -0
  334. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js.map +1 -0
  335. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +228 -0
  336. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -0
  337. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js +142 -0
  338. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js.map +1 -0
  339. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js +309 -0
  340. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js.map +1 -0
  341. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js +120 -0
  342. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js.map +1 -0
  343. package/build/dist/Server/Utils/Database/MigrationFailureLog.js +174 -0
  344. package/build/dist/Server/Utils/Database/MigrationFailureLog.js.map +1 -0
  345. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js +30 -0
  346. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js.map +1 -0
  347. package/build/dist/Server/Utils/LLM/LLMService.js +452 -92
  348. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  349. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js +11 -8
  350. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js.map +1 -1
  351. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +11 -8
  352. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  353. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +378 -15
  354. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  355. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +59 -0
  356. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  357. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  358. package/build/dist/Types/AI/AIChatMessageRole.js +7 -0
  359. package/build/dist/Types/AI/AIChatMessageRole.js.map +1 -0
  360. package/build/dist/Types/AI/AIChatMessageStatus.js +27 -0
  361. package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -0
  362. package/build/dist/Types/AI/AIChatPermissionMode.js +53 -0
  363. package/build/dist/Types/AI/AIChatPermissionMode.js.map +1 -0
  364. package/build/dist/Types/AI/AIChatTypes.js +74 -0
  365. package/build/dist/Types/AI/AIChatTypes.js.map +1 -0
  366. package/build/dist/Types/AI/AIRunEventType.js +18 -0
  367. package/build/dist/Types/AI/AIRunEventType.js.map +1 -0
  368. package/build/dist/Types/AI/AIRunStatus.js +26 -0
  369. package/build/dist/Types/AI/AIRunStatus.js.map +1 -0
  370. package/build/dist/Types/AI/AIRunType.js +7 -0
  371. package/build/dist/Types/AI/AIRunType.js.map +1 -0
  372. package/build/dist/Types/Date.js +153 -15
  373. package/build/dist/Types/Date.js.map +1 -1
  374. package/build/dist/Types/LLM/LlmType.js +6 -0
  375. package/build/dist/Types/LLM/LlmType.js.map +1 -1
  376. package/build/dist/Types/OnCallDutyPolicy/Layer.js +602 -171
  377. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  378. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js +27 -13
  379. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js.map +1 -1
  380. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +20 -5
  381. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
  382. package/build/dist/UI/Components/Events/RecurringFieldElement.js +13 -0
  383. package/build/dist/UI/Components/Events/RecurringFieldElement.js.map +1 -1
  384. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +10 -5
  385. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  386. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +18 -4
  387. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  388. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  389. package/build/dist/UI/Components/Page/Page.js +3 -1
  390. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  391. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +1 -1
  392. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  393. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js +38 -0
  394. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js.map +1 -0
  395. package/build/dist/UI/Utils/TestLLMProvider.js +37 -0
  396. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -0
  397. package/package.json +1 -1
@@ -0,0 +1,386 @@
1
+ import API from "../../../../Utils/API";
2
+ import HTTPResponse from "../../../../Types/API/HTTPResponse";
3
+ import { JSONObject } from "../../../../Types/JSON";
4
+ import LlmType from "../../../../Types/LLM/LlmType";
5
+ import LLMService, {
6
+ LLMCompletionResponse,
7
+ } from "../../../../Server/Utils/LLM/LLMService";
8
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
9
+
10
+ type PostSpy = ReturnType<typeof jest.spyOn>;
11
+
12
+ function mockPostResponse(jsonData: JSONObject): PostSpy {
13
+ return jest.spyOn(API, "post").mockResolvedValue({
14
+ jsonData,
15
+ } as unknown as HTTPResponse<JSONObject>) as PostSpy;
16
+ }
17
+
18
+ afterEach(() => {
19
+ jest.restoreAllMocks();
20
+ });
21
+
22
+ describe("LLMService tool calling — OpenAI-compatible", () => {
23
+ test("serializes tools and parses tool_calls", async () => {
24
+ const spy: PostSpy = mockPostResponse({
25
+ choices: [
26
+ {
27
+ message: {
28
+ content: null,
29
+ tool_calls: [
30
+ {
31
+ id: "call_1",
32
+ type: "function",
33
+ function: {
34
+ name: "search_logs",
35
+ arguments: '{"traceId":"abc"}',
36
+ },
37
+ },
38
+ ],
39
+ },
40
+ },
41
+ ],
42
+ usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
43
+ });
44
+
45
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
46
+ llmProviderConfig: { llmType: LlmType.OpenAI, apiKey: "test-key" },
47
+ messages: [{ role: "user", content: "find logs" }],
48
+ tools: [
49
+ {
50
+ name: "search_logs",
51
+ description: "search logs",
52
+ inputSchema: { type: "object", properties: {} },
53
+ },
54
+ ],
55
+ maxTokens: 1024,
56
+ });
57
+
58
+ expect(response.stopReason).toBe("tool_use");
59
+ expect(response.toolCalls).toHaveLength(1);
60
+ expect(response.toolCalls![0]!.name).toBe("search_logs");
61
+ expect(response.toolCalls![0]!.arguments).toEqual({ traceId: "abc" });
62
+
63
+ const requestBody: JSONObject = (
64
+ spy.mock.calls[0]![0] as { data: JSONObject }
65
+ ).data;
66
+ expect(requestBody["max_tokens"]).toBe(1024);
67
+ expect(requestBody["tools"]).toHaveLength(1);
68
+ });
69
+
70
+ test("tolerates malformed tool-call argument JSON", async () => {
71
+ mockPostResponse({
72
+ choices: [
73
+ {
74
+ message: {
75
+ content: null,
76
+ tool_calls: [
77
+ {
78
+ id: "call_1",
79
+ type: "function",
80
+ function: { name: "search_logs", arguments: "{not-json" },
81
+ },
82
+ ],
83
+ },
84
+ },
85
+ ],
86
+ });
87
+
88
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
89
+ llmProviderConfig: { llmType: LlmType.OpenAI, apiKey: "test-key" },
90
+ messages: [{ role: "user", content: "hi" }],
91
+ });
92
+
93
+ expect(response.toolCalls![0]!.arguments).toEqual({});
94
+ });
95
+ });
96
+
97
+ describe("LLMService tool calling — Anthropic", () => {
98
+ test("always sends the required max_tokens and parses tool_use blocks", async () => {
99
+ const spy: PostSpy = mockPostResponse({
100
+ content: [
101
+ {
102
+ type: "tool_use",
103
+ id: "toolu_1",
104
+ name: "query_metrics",
105
+ input: { metricName: "cpu" },
106
+ },
107
+ ],
108
+ stop_reason: "tool_use",
109
+ usage: { input_tokens: 20, output_tokens: 10 },
110
+ });
111
+
112
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
113
+ llmProviderConfig: { llmType: LlmType.Anthropic, apiKey: "test-key" },
114
+ messages: [
115
+ { role: "system", content: "be helpful" },
116
+ { role: "user", content: "cpu usage?" },
117
+ ],
118
+ tools: [
119
+ {
120
+ name: "query_metrics",
121
+ description: "query metrics",
122
+ inputSchema: { type: "object", properties: {} },
123
+ },
124
+ ],
125
+ });
126
+
127
+ const requestBody: JSONObject = (
128
+ spy.mock.calls[0]![0] as { data: JSONObject }
129
+ ).data;
130
+
131
+ // max_tokens is required by the Anthropic API — previously missing.
132
+ expect(requestBody["max_tokens"]).toBe(4096);
133
+ expect(
134
+ (requestBody["tools"] as Array<JSONObject>)[0]!["input_schema"],
135
+ ).toBeDefined();
136
+
137
+ // A tool_use-only response must not throw "No text content".
138
+ expect(response.content).toBe("");
139
+ expect(response.stopReason).toBe("tool_use");
140
+ expect(response.toolCalls).toHaveLength(1);
141
+ expect(response.toolCalls![0]!.arguments).toEqual({ metricName: "cpu" });
142
+ expect(response.usage!.totalTokens).toBe(30);
143
+ });
144
+
145
+ test("merges consecutive tool results into one user message", async () => {
146
+ const spy: PostSpy = mockPostResponse({
147
+ content: [{ type: "text", text: "done" }],
148
+ stop_reason: "end_turn",
149
+ usage: { input_tokens: 5, output_tokens: 5 },
150
+ });
151
+
152
+ await LLMService.getCompletion({
153
+ llmProviderConfig: { llmType: LlmType.Anthropic, apiKey: "test-key" },
154
+ messages: [
155
+ { role: "user", content: "check two things" },
156
+ {
157
+ role: "assistant",
158
+ content: "",
159
+ toolCalls: [
160
+ { id: "t1", name: "query_incidents", arguments: {} },
161
+ { id: "t2", name: "query_alerts", arguments: {} },
162
+ ],
163
+ },
164
+ { role: "tool", toolCallId: "t1", content: "incidents: none" },
165
+ { role: "tool", toolCallId: "t2", content: "alerts: none" },
166
+ ],
167
+ });
168
+
169
+ const requestBody: JSONObject = (
170
+ spy.mock.calls[0]![0] as { data: JSONObject }
171
+ ).data;
172
+ const messages: Array<JSONObject> = requestBody[
173
+ "messages"
174
+ ] as Array<JSONObject>;
175
+
176
+ // user, assistant(tool_use), single merged user(tool_results)
177
+ expect(messages).toHaveLength(3);
178
+ const merged: Array<JSONObject> = messages[2]![
179
+ "content"
180
+ ] as Array<JSONObject>;
181
+ expect(merged).toHaveLength(2);
182
+ expect(merged[0]!["type"]).toBe("tool_result");
183
+ expect(merged[1]!["tool_use_id"]).toBe("t2");
184
+ });
185
+ });
186
+
187
+ describe("LLMService tool calling — Ollama", () => {
188
+ test("works without an API key and parses object tool arguments", async () => {
189
+ const spy: PostSpy = mockPostResponse({
190
+ message: {
191
+ content: "",
192
+ tool_calls: [
193
+ {
194
+ function: {
195
+ name: "top_exceptions",
196
+ arguments: { limit: 5 },
197
+ },
198
+ },
199
+ ],
200
+ },
201
+ });
202
+
203
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
204
+ // No apiKey — keyless self-hosted Ollama must keep working.
205
+ llmProviderConfig: {
206
+ llmType: LlmType.Ollama,
207
+ baseUrl: "http://localhost:11434",
208
+ },
209
+ messages: [{ role: "user", content: "top exceptions" }],
210
+ tools: [
211
+ {
212
+ name: "top_exceptions",
213
+ description: "top exceptions",
214
+ inputSchema: { type: "object", properties: {} },
215
+ },
216
+ ],
217
+ });
218
+
219
+ expect(response.toolCalls).toHaveLength(1);
220
+ expect(response.toolCalls![0]!.arguments).toEqual({ limit: 5 });
221
+ expect(response.toolCalls![0]!.id).toBe("tool_call_0");
222
+
223
+ const requestBody: JSONObject = (
224
+ spy.mock.calls[0]![0] as { data: JSONObject }
225
+ ).data;
226
+ expect(requestBody["tools"]).toHaveLength(1);
227
+ expect(requestBody["stream"]).toBe(false);
228
+ });
229
+ });
230
+
231
+ describe("LLMService — OpenAI-compatible (generic, e.g. vLLM)", () => {
232
+ test("works without an API key and omits the Authorization header", async () => {
233
+ const spy: PostSpy = mockPostResponse({
234
+ choices: [{ message: { content: "OK" } }],
235
+ usage: { prompt_tokens: 3, completion_tokens: 1, total_tokens: 4 },
236
+ });
237
+
238
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
239
+ // No apiKey — a keyless self-hosted vLLM server must work.
240
+ llmProviderConfig: {
241
+ llmType: LlmType.OpenAICompatible,
242
+ baseUrl: "http://vllm.local:8000/v1",
243
+ modelName: "meta-llama/Llama-3.1-8B-Instruct",
244
+ },
245
+ messages: [{ role: "user", content: "ping" }],
246
+ });
247
+
248
+ expect(response.content).toBe("OK");
249
+
250
+ const call: {
251
+ url: { toString: () => string };
252
+ data: JSONObject;
253
+ headers: JSONObject;
254
+ } = spy.mock.calls[0]![0] as {
255
+ url: { toString: () => string };
256
+ data: JSONObject;
257
+ headers: JSONObject;
258
+ };
259
+ expect(call.url.toString()).toContain("/v1/chat/completions");
260
+ expect(call.data["model"]).toBe("meta-llama/Llama-3.1-8B-Instruct");
261
+ expect(call.headers["Authorization"]).toBeUndefined();
262
+ });
263
+
264
+ test("sends the Authorization header when an API key is provided", async () => {
265
+ const spy: PostSpy = mockPostResponse({
266
+ choices: [{ message: { content: "OK" } }],
267
+ });
268
+
269
+ await LLMService.getCompletion({
270
+ llmProviderConfig: {
271
+ llmType: LlmType.OpenAICompatible,
272
+ baseUrl: "http://vllm.local:8000/v1",
273
+ modelName: "my-model",
274
+ apiKey: "secret",
275
+ },
276
+ messages: [{ role: "user", content: "ping" }],
277
+ });
278
+
279
+ const call: { headers: JSONObject } = spy.mock.calls[0]![0] as {
280
+ headers: JSONObject;
281
+ };
282
+ expect(call.headers["Authorization"]).toBe("Bearer secret");
283
+ });
284
+
285
+ test("requires a base URL", async () => {
286
+ await expect(
287
+ LLMService.getCompletion({
288
+ llmProviderConfig: {
289
+ llmType: LlmType.OpenAICompatible,
290
+ modelName: "my-model",
291
+ },
292
+ messages: [{ role: "user", content: "ping" }],
293
+ }),
294
+ ).rejects.toThrow("Base URL is required");
295
+ });
296
+
297
+ test("requires a model name", async () => {
298
+ await expect(
299
+ LLMService.getCompletion({
300
+ llmProviderConfig: {
301
+ llmType: LlmType.OpenAICompatible,
302
+ baseUrl: "http://vllm.local:8000/v1",
303
+ },
304
+ messages: [{ role: "user", content: "ping" }],
305
+ }),
306
+ ).rejects.toThrow("Model Name is required");
307
+ });
308
+ });
309
+
310
+ describe("LLMService — prompt caching", () => {
311
+ test("Anthropic marks system and the last tool with an ephemeral cache breakpoint", async () => {
312
+ const spy: PostSpy = mockPostResponse({
313
+ content: [{ type: "text", text: "hi" }],
314
+ stop_reason: "end_turn",
315
+ usage: {
316
+ input_tokens: 12,
317
+ output_tokens: 4,
318
+ cache_read_input_tokens: 100,
319
+ cache_creation_input_tokens: 8,
320
+ },
321
+ });
322
+
323
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
324
+ llmProviderConfig: { llmType: LlmType.Anthropic, apiKey: "test-key" },
325
+ messages: [
326
+ { role: "system", content: "be helpful" },
327
+ { role: "user", content: "hi" },
328
+ ],
329
+ tools: [
330
+ {
331
+ name: "a",
332
+ description: "a",
333
+ inputSchema: { type: "object", properties: {} },
334
+ },
335
+ {
336
+ name: "b",
337
+ description: "b",
338
+ inputSchema: { type: "object", properties: {} },
339
+ },
340
+ ],
341
+ });
342
+
343
+ const requestBody: JSONObject = (
344
+ spy.mock.calls[0]![0] as { data: JSONObject }
345
+ ).data;
346
+
347
+ // The system prompt is sent as a content-block array with a cache breakpoint.
348
+ const systemBlocks: Array<JSONObject> = requestBody[
349
+ "system"
350
+ ] as Array<JSONObject>;
351
+ expect(Array.isArray(systemBlocks)).toBe(true);
352
+ expect(systemBlocks[0]!["cache_control"]).toEqual({ type: "ephemeral" });
353
+
354
+ // Only the last tool carries the breakpoint (it caches the whole block).
355
+ const tools: Array<JSONObject> = requestBody["tools"] as Array<JSONObject>;
356
+ expect(tools[tools.length - 1]!["cache_control"]).toEqual({
357
+ type: "ephemeral",
358
+ });
359
+ expect(tools[0]!["cache_control"]).toBeUndefined();
360
+
361
+ // totalTokens folds in cached + cache-creation input tokens (12+100+8+4).
362
+ expect(response.usage!.totalTokens).toBe(124);
363
+ expect(response.usage!.cachedInputTokens).toBe(100);
364
+ expect(response.usage!.cacheCreationTokens).toBe(8);
365
+ });
366
+
367
+ test("OpenAI surfaces cached prompt tokens from prompt_tokens_details", async () => {
368
+ mockPostResponse({
369
+ choices: [{ message: { content: "ok" } }],
370
+ usage: {
371
+ prompt_tokens: 50,
372
+ completion_tokens: 5,
373
+ total_tokens: 55,
374
+ prompt_tokens_details: { cached_tokens: 40 },
375
+ },
376
+ });
377
+
378
+ const response: LLMCompletionResponse = await LLMService.getCompletion({
379
+ llmProviderConfig: { llmType: LlmType.OpenAI, apiKey: "test-key" },
380
+ messages: [{ role: "user", content: "hi" }],
381
+ });
382
+
383
+ expect(response.usage!.cachedInputTokens).toBe(40);
384
+ expect(response.usage!.totalTokens).toBe(55);
385
+ });
386
+ });
@@ -0,0 +1,62 @@
1
+ import { ToolArgs } from "../../../../Server/Utils/AI/Toolbox/ToolTypes";
2
+ import BadDataException from "../../../../Types/Exception/BadDataException";
3
+ import { JSONObject } from "../../../../Types/JSON";
4
+ import { describe, expect, test } from "@jest/globals";
5
+
6
+ /*
7
+ * getTimeRange turns untrusted LLM-supplied time arguments into a concrete
8
+ * window. It must reject garbage rather than silently answer for the default
9
+ * window (which would answer a different question than the user asked).
10
+ */
11
+ describe("ToolArgs.getTimeRange", () => {
12
+ test("uses explicit ISO 8601 start and end", () => {
13
+ const args: JSONObject = {
14
+ startTime: "2024-01-31T13:00:00Z",
15
+ endTime: "2024-01-31T14:00:00Z",
16
+ };
17
+ const { startTime, endTime } = ToolArgs.getTimeRange(args, {
18
+ defaultHours: 1,
19
+ maxDays: 30,
20
+ });
21
+ expect(startTime.toISOString()).toBe("2024-01-31T13:00:00.000Z");
22
+ expect(endTime.toISOString()).toBe("2024-01-31T14:00:00.000Z");
23
+ });
24
+
25
+ test("throws on an unparseable endTime instead of falling back", () => {
26
+ expect(() => {
27
+ ToolArgs.getTimeRange({ endTime: "yesterday 2am" }, { defaultHours: 1 });
28
+ }).toThrow(BadDataException);
29
+ });
30
+
31
+ test("throws on an unparseable startTime instead of falling back", () => {
32
+ expect(() => {
33
+ ToolArgs.getTimeRange(
34
+ { startTime: "last tuesday", endTime: "2024-01-31T14:00:00Z" },
35
+ { defaultHours: 1 },
36
+ );
37
+ }).toThrow(BadDataException);
38
+ });
39
+
40
+ test("defaults the window when no timestamps are supplied", () => {
41
+ const { startTime, endTime } = ToolArgs.getTimeRange(
42
+ {},
43
+ { defaultHours: 2 },
44
+ );
45
+ const spanHours: number =
46
+ (endTime.getTime() - startTime.getTime()) / (60 * 60 * 1000);
47
+ expect(spanHours).toBeCloseTo(2, 5);
48
+ });
49
+
50
+ test("clamps a window wider than maxDays", () => {
51
+ const { startTime, endTime } = ToolArgs.getTimeRange(
52
+ {
53
+ startTime: "2024-01-01T00:00:00Z",
54
+ endTime: "2024-06-01T00:00:00Z",
55
+ },
56
+ { defaultHours: 1, maxDays: 30 },
57
+ );
58
+ const spanDays: number =
59
+ (endTime.getTime() - startTime.getTime()) / (24 * 60 * 60 * 1000);
60
+ expect(spanDays).toBeLessThanOrEqual(30);
61
+ });
62
+ });
@@ -0,0 +1,79 @@
1
+ import { ToolArgs } from "../../../../Server/Utils/AI/Toolbox/ToolTypes";
2
+ import ObjectID from "../../../../Types/ObjectID";
3
+ import { describe, expect, test } from "@jest/globals";
4
+
5
+ /*
6
+ * scopeServiceIds decides the `serviceIds` filter the aggregation tools hand to
7
+ * the raw-SQL aggregation services. The aggregation services treat a
8
+ * missing/empty serviceIds as "no filter" (whole project), so for a
9
+ * label-restricted user this helper must NEVER return undefined or []. These
10
+ * tests pin that invariant.
11
+ */
12
+ describe("ToolArgs.scopeServiceIds", () => {
13
+ test("unrestricted user, no requested service → no filter", () => {
14
+ expect(ToolArgs.scopeServiceIds(null, undefined)).toBeUndefined();
15
+ });
16
+
17
+ test("unrestricted user with a requested service → just that service", () => {
18
+ const requested: ObjectID = ObjectID.generate();
19
+ const result: Array<ObjectID> | undefined = ToolArgs.scopeServiceIds(
20
+ null,
21
+ requested,
22
+ );
23
+ expect(
24
+ result?.map((id: ObjectID) => {
25
+ return id.toString();
26
+ }),
27
+ ).toEqual([requested.toString()]);
28
+ });
29
+
30
+ test("restricted user, no requested service → the accessible set", () => {
31
+ const a: ObjectID = ObjectID.generate();
32
+ const b: ObjectID = ObjectID.generate();
33
+ const result: Array<ObjectID> | undefined = ToolArgs.scopeServiceIds(
34
+ [a, b],
35
+ undefined,
36
+ );
37
+ expect(
38
+ result?.map((id: ObjectID) => {
39
+ return id.toString();
40
+ }),
41
+ ).toEqual([a.toString(), b.toString()]);
42
+ });
43
+
44
+ test("restricted user requesting an accessible service → intersection", () => {
45
+ const a: ObjectID = ObjectID.generate();
46
+ const b: ObjectID = ObjectID.generate();
47
+ const result: Array<ObjectID> | undefined = ToolArgs.scopeServiceIds(
48
+ [a, b],
49
+ b,
50
+ );
51
+ expect(
52
+ result?.map((id: ObjectID) => {
53
+ return id.toString();
54
+ }),
55
+ ).toEqual([b.toString()]);
56
+ });
57
+
58
+ test("restricted user requesting a forbidden service → no-match sentinel, never empty", () => {
59
+ const accessible: ObjectID = ObjectID.generate();
60
+ const forbidden: ObjectID = ObjectID.generate();
61
+ const result: Array<ObjectID> | undefined = ToolArgs.scopeServiceIds(
62
+ [accessible],
63
+ forbidden,
64
+ );
65
+ expect(result).toBeDefined();
66
+ expect(result).toHaveLength(1);
67
+ expect(result?.[0]?.toString()).toBe(ObjectID.getZeroObjectID().toString());
68
+ });
69
+
70
+ test("restricted user with no accessible services → no-match sentinel, never empty", () => {
71
+ const result: Array<ObjectID> | undefined = ToolArgs.scopeServiceIds(
72
+ [],
73
+ undefined,
74
+ );
75
+ expect(result).toBeDefined();
76
+ expect(result).toHaveLength(1);
77
+ expect(result?.[0]?.toString()).toBe(ObjectID.getZeroObjectID().toString());
78
+ });
79
+ });