@oneuptime/common 11.3.26 → 11.4.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.
- package/Models/DatabaseModels/AIRun.ts +50 -0
- package/Models/DatabaseModels/IncidentEpisodeRoleMember.ts +1 -1
- package/Models/DatabaseModels/IncidentMember.ts +1 -1
- package/Models/DatabaseModels/IncomingCallPolicy.ts +13 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/MigrationFailure.ts +170 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +51 -2
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +44 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +6 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.ts +6 -0
- package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +1 -1
- package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +2 -2
- package/Models/DatabaseModels/Project.ts +60 -0
- package/Server/API/AIInvestigationAPI.ts +148 -0
- package/Server/API/AlertAPI.ts +1 -1
- package/Server/API/IncidentAPI.ts +2 -2
- package/Server/API/IncidentEpisodeAPI.ts +1 -1
- package/Server/API/LlmProviderAPI.ts +1 -0
- package/Server/API/ScheduledMaintenanceAPI.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.ts +81 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.ts +35 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783598145111-AddEnableAutomaticIncidentInvestigationToProject.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783615884106-AddInvestigationSubjectToAIRun.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783632447975-AddEnableAutomaticAlertInvestigationToProject.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
- package/Server/Infrastructure/PostgresDatabase.ts +11 -0
- package/Server/Services/AIService.ts +74 -2
- package/Server/Services/AlertService.ts +25 -0
- package/Server/Services/AnalyticsDatabaseService.ts +10 -1
- package/Server/Services/DatabaseService.ts +10 -1
- package/Server/Services/IncidentService.ts +26 -1
- package/Server/Services/IncidentStateTimelineService.ts +19 -0
- package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +75 -2
- package/Server/Services/IncomingCallPolicyService.ts +42 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MigrationFailureService.ts +9 -0
- package/Server/Services/MonitorProbeService.ts +33 -7
- package/Server/Services/MonitorService.ts +19 -7
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +185 -41
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +23 -15
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +39 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +11 -2
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +502 -26
- package/Server/Services/OnCallDutyPolicyTimeLogService.ts +49 -7
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +218 -4
- package/Server/Services/ProjectCallSMSConfigService.ts +82 -1
- package/Server/Services/TeamMemberService.ts +6 -0
- package/Server/Services/UserNotificationRuleService.ts +13 -42
- package/Server/Services/UserOnCallLogService.ts +90 -0
- package/Server/Services/UserOnCallLogTimelineService.ts +43 -1
- package/Server/Types/Database/QueryUtil.ts +57 -0
- package/Server/Utils/AI/AlertAIContextBuilder.ts +6 -1
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +14 -2
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +119 -11
- package/Server/Utils/AI/IncidentAIContextBuilder.ts +18 -3
- package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +6 -1
- package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +12 -2
- package/Server/Utils/AI/Sentinel/AlertInvestigationRunner.ts +141 -0
- package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +178 -0
- package/Server/Utils/AI/Sentinel/IncidentPostmortemRunner.ts +105 -0
- package/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.ts +405 -0
- package/Server/Utils/AI/Sentinel/SentinelMemory.ts +167 -0
- package/Server/Utils/AI/Toolbox/IncidentTools.ts +183 -1
- package/Server/Utils/AI/Toolbox/Index.ts +15 -1
- package/Server/Utils/AI/Toolbox/RecentChangesTools.ts +208 -0
- package/Server/Utils/AI/Toolbox/SentinelActionTools.ts +577 -0
- package/Server/Utils/AI/Toolbox/Serializer.ts +42 -0
- package/Server/Utils/Database/MigrationFailureLog.ts +240 -0
- package/Server/Utils/IncomingCallPhoneNumber.ts +41 -0
- package/Server/Utils/LLM/LLMService.ts +110 -11
- package/Server/Utils/Telemetry/IoTSnapshotScan.ts +12 -9
- package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +12 -9
- package/Tests/Server/API/BaseAPI.test.ts +1 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +0 -8
- package/Tests/Server/Services/OnCallDutyPolicyScheduleLayerUserReorder.test.ts +233 -0
- package/Tests/Server/Services/OnCallDutyPolicyTimeLogServiceScoping.test.ts +242 -0
- package/Tests/Server/Services/OnCallDutyPolicyUserOverrideEdit.test.ts +198 -0
- package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +495 -0
- package/Tests/Server/Types/Database/QueryUtil.test.ts +74 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +78 -0
- package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +68 -0
- package/Tests/Types/DateExhaustiveTimezone.test.ts +700 -0
- package/Tests/Types/DateTimezoneWallClock.test.ts +99 -0
- package/Tests/Types/Events/Recurring.test.ts +22 -9
- package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixes.test.ts +291 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixesRound2.test.ts +398 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeekendGap.test.ts +114 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeeklyDayShift.test.ts +76 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyMutation.test.ts +128 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyProbe.test.ts +203 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilDiffFuzz.test.ts +322 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilEdgeCases.test.ts +280 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveCurrentUser.test.ts +863 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveDaily.test.ts +900 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveMultiLayer.test.ts +1104 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +957 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveWeekly.test.ts +1095 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilInvariants.test.ts +232 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +227 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMonthYearAudit.test.ts +255 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerAudit.test.ts +388 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerEdge.test.ts +300 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilOvernightDSTAudit.test.ts +158 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapFix.test.ts +253 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapRepro.test.ts +157 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilRotationFixes.test.ts +414 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilTimezone.test.ts +243 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilWeekendGapRepro.test.ts +112 -0
- package/Tests/Types/OnCallDutyPolicy/OverrideLensAudit.test.ts +117 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimes.test.ts +8 -6
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesDefaultDayAudit.test.ts +112 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesExhaustive.test.ts +821 -0
- package/Tests/Types/OnCallDutyPolicy/RestrictionTimesMutationInvariant.test.ts +886 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtil.test.ts +260 -0
- package/Tests/Types/OnCallDutyPolicy/UserOverrideUtil.test.ts +255 -0
- package/Tests/Types/OnCallDutyPolicy/UserOverrideUtilExhaustive.test.ts +1126 -0
- package/Types/Date.ts +246 -15
- package/Types/OnCallDutyPolicy/Layer.ts +790 -260
- package/Types/OnCallDutyPolicy/RestrictionTimes.ts +39 -13
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +257 -0
- package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +21 -5
- package/UI/Components/Calendar/Calendar.tsx +8 -2
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +5 -5
- package/UI/Components/Events/RecurringFieldElement.tsx +16 -0
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +8 -0
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +1 -1
- package/build/dist/Models/DatabaseModels/AIRun.js +52 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +10 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MigrationFailure.js +196 -0
- package/build/dist/Models/DatabaseModels/MigrationFailure.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +52 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +45 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +6 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js +6 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +2 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +62 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +107 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -0
- package/build/dist/Server/API/AlertAPI.js +1 -1
- package/build/dist/Server/API/IncidentAPI.js +2 -2
- package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +1 -0
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783598145111-AddEnableAutomaticIncidentInvestigationToProject.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783598145111-AddEnableAutomaticIncidentInvestigationToProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783615884106-AddInvestigationSubjectToAIRun.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783615884106-AddInvestigationSubjectToAIRun.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783632447975-AddEnableAutomaticAlertInvestigationToProject.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783632447975-AddEnableAutomaticAlertInvestigationToProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/PostgresDatabase.js +9 -0
- package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +53 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +24 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +10 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +10 -1
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +25 -1
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +55 -2
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyService.js +40 -0
- package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MigrationFailureService.js +9 -0
- package/build/dist/Server/Services/MigrationFailureService.js.map +1 -0
- package/build/dist/Server/Services/MonitorProbeService.js +33 -7
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +12 -5
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +81 -22
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +134 -31
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +21 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +36 -0
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +121 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +11 -2
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +409 -36
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +52 -8
- package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +170 -3
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/ProjectCallSMSConfigService.js +72 -0
- package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +6 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +12 -30
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +75 -0
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js +31 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +45 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +6 -1
- package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +13 -2
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +59 -11
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +18 -3
- package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +6 -1
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +12 -2
- package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -1
- package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js +119 -0
- package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +147 -0
- package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/Sentinel/IncidentPostmortemRunner.js +93 -0
- package/build/dist/Server/Utils/AI/Sentinel/IncidentPostmortemRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js +311 -0
- package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +1 -0
- package/build/dist/Server/Utils/AI/Sentinel/SentinelMemory.js +143 -0
- package/build/dist/Server/Utils/AI/Sentinel/SentinelMemory.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +152 -1
- package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +10 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js +165 -0
- package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SentinelActionTools.js +451 -0
- package/build/dist/Server/Utils/AI/Toolbox/SentinelActionTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +40 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
- package/build/dist/Server/Utils/Database/MigrationFailureLog.js +174 -0
- package/build/dist/Server/Utils/Database/MigrationFailureLog.js.map +1 -0
- package/build/dist/Server/Utils/IncomingCallPhoneNumber.js +30 -0
- package/build/dist/Server/Utils/IncomingCallPhoneNumber.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +81 -5
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js +11 -8
- package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +11 -8
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
- package/build/dist/Types/Date.js +185 -15
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +602 -171
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js +27 -13
- package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +159 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +20 -5
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
- package/build/dist/UI/Components/Calendar/Calendar.js +2 -2
- package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Events/RecurringFieldElement.js +13 -0
- package/build/dist/UI/Components/Events/RecurringFieldElement.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import { DataSource, DataSourceOptions } from "typeorm";
|
|
3
|
+
import logger from "../Logger";
|
|
4
|
+
import { AppVersion } from "../../EnvironmentConfig";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Records migrations that FAILED to apply into the "MigrationFailure" table so
|
|
8
|
+
* the admin health page can explain WHY a migration is pending (what error,
|
|
9
|
+
* when it ran) instead of only showing that it is behind. Every write here is
|
|
10
|
+
* best-effort: a diagnostic log must never itself crash a boot / migrate Job or
|
|
11
|
+
* mask the real migration error, so all failures inside this module are
|
|
12
|
+
* swallowed (logged, not thrown).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Which runner a failed migration belongs to. Stored verbatim in the table.
|
|
16
|
+
export enum MigrationFailureType {
|
|
17
|
+
PostgresSchema = "PostgresSchema",
|
|
18
|
+
DataMigration = "DataMigration",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Keep a single row bounded so a pathological error/stack can't bloat the table.
|
|
22
|
+
const MAX_ERROR_MESSAGE_LENGTH: number = 10000;
|
|
23
|
+
const MAX_ERROR_STACK_LENGTH: number = 20000;
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* Best-effort credential scrub for the free-form error text we persist. DB /
|
|
27
|
+
* migration errors seldom carry secrets, but a connection error can echo a
|
|
28
|
+
* `scheme://user:pass@host` DSN and a failing DDL can quote a literal default,
|
|
29
|
+
* so we mask the obvious vectors before the text is stored and later shown.
|
|
30
|
+
*/
|
|
31
|
+
const CONNECTION_STRING_SECRET_PATTERN: RegExp =
|
|
32
|
+
/([a-z][a-z0-9+.-]*:\/\/[^:@\s/]+):[^\s/]+@/gi;
|
|
33
|
+
const KEYWORD_SECRET_PATTERN: RegExp =
|
|
34
|
+
/(password|secret|token|api[_-]?key|apikey|credential|private[_-]?key|auth[_-]?token|access[_-]?key)(\s*[:=]\s*)('(?:[^']|'')*'|"[^"]*"|[^\s,)]+)/gi;
|
|
35
|
+
|
|
36
|
+
export function scrubMigrationErrorText(text: string): string {
|
|
37
|
+
if (!text) {
|
|
38
|
+
return text;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return text
|
|
42
|
+
.replace(
|
|
43
|
+
CONNECTION_STRING_SECRET_PATTERN,
|
|
44
|
+
(_match: string, prefix: string): string => {
|
|
45
|
+
return `${prefix}:***REDACTED***@`;
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
.replace(
|
|
49
|
+
KEYWORD_SECRET_PATTERN,
|
|
50
|
+
(_match: string, keyword: string, separator: string): string => {
|
|
51
|
+
return `${keyword}${separator}***REDACTED***`;
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function toErrorMessage(error: unknown): string {
|
|
57
|
+
if (error instanceof Error) {
|
|
58
|
+
return error.message || error.name || "Unknown error";
|
|
59
|
+
}
|
|
60
|
+
return String(error);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toErrorStack(error: unknown): string | null {
|
|
64
|
+
return error instanceof Error && error.stack ? error.stack : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface MigrationFailureInput {
|
|
68
|
+
migrationName: string;
|
|
69
|
+
migrationType: MigrationFailureType;
|
|
70
|
+
error: unknown;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* Append one failed-attempt row using the provided (already-connected)
|
|
75
|
+
* DataSource. Raw SQL — not the Service layer — so it also works on a
|
|
76
|
+
* throwaway diagnostic connection and never depends on realtime/event wiring.
|
|
77
|
+
* Returns true if the row was written. If the "MigrationFailure" table does not
|
|
78
|
+
* exist yet (e.g. its own migration is still pending on a first rollout) the
|
|
79
|
+
* INSERT throws and is swallowed — the caller's real error is unaffected.
|
|
80
|
+
*/
|
|
81
|
+
export async function recordMigrationFailure(
|
|
82
|
+
dataSource: DataSource,
|
|
83
|
+
input: MigrationFailureInput,
|
|
84
|
+
): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
const message: string = scrubMigrationErrorText(
|
|
87
|
+
toErrorMessage(input.error),
|
|
88
|
+
).substring(0, MAX_ERROR_MESSAGE_LENGTH);
|
|
89
|
+
|
|
90
|
+
const rawStack: string | null = toErrorStack(input.error);
|
|
91
|
+
const stack: string | null = rawStack
|
|
92
|
+
? scrubMigrationErrorText(rawStack).substring(0, MAX_ERROR_STACK_LENGTH)
|
|
93
|
+
: null;
|
|
94
|
+
|
|
95
|
+
await dataSource.query(
|
|
96
|
+
`INSERT INTO "MigrationFailure"
|
|
97
|
+
("migrationName", "migrationType", "errorMessage", "errorStack", "attemptedAt", "hostName", "appVersion", "version", "createdAt", "updatedAt")
|
|
98
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, 1, now(), now())`,
|
|
99
|
+
[
|
|
100
|
+
input.migrationName,
|
|
101
|
+
input.migrationType,
|
|
102
|
+
message,
|
|
103
|
+
stack,
|
|
104
|
+
new Date(),
|
|
105
|
+
os.hostname(),
|
|
106
|
+
AppVersion,
|
|
107
|
+
],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
// Diagnostic write must never mask the real failure — log and move on.
|
|
113
|
+
logger.warn(
|
|
114
|
+
`Could not record migration failure for "${input.migrationName}" (${input.migrationType}); continuing.`,
|
|
115
|
+
);
|
|
116
|
+
logger.warn(err);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Trailing epoch in a migration class name — how TypeORM orders/identifies them.
|
|
122
|
+
function parseMigrationTimestamp(name: string): number {
|
|
123
|
+
const match: RegExpMatchArray | null = name.match(/(\d{10,})$/);
|
|
124
|
+
return match ? Number(match[1]) : 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
* The TypeORM schema runner (migrationsRun) applies migrations in ascending
|
|
129
|
+
* timestamp order and halts at the first failure, so the FIRST defined
|
|
130
|
+
* migration not yet in the `migrations` table is exactly the one that failed.
|
|
131
|
+
* We recompute it here from a throwaway connection because the app's own
|
|
132
|
+
* connect() has already failed (its DataSource is not usable) at the point a
|
|
133
|
+
* schema migration throws.
|
|
134
|
+
*/
|
|
135
|
+
export async function recordSchemaMigrationFailureBestEffort(
|
|
136
|
+
dataSourceOptions: DataSourceOptions,
|
|
137
|
+
originalError: unknown,
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
/*
|
|
140
|
+
* Only THIS process's own boot runs schema migrations (migrationsRun=true —
|
|
141
|
+
* the migrate Job and single-pod / dev boots). On runtime pods where a
|
|
142
|
+
* dedicated migrate Job owns migrations (migrationsRun=false), a connect()
|
|
143
|
+
* failure is a connectivity problem, never a failed migration — recording
|
|
144
|
+
* one here would misattribute an outage to a (legitimately) pending
|
|
145
|
+
* migration, so skip.
|
|
146
|
+
*/
|
|
147
|
+
if (
|
|
148
|
+
(dataSourceOptions as { migrationsRun?: boolean }).migrationsRun !== true
|
|
149
|
+
) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let diagnosticDataSource: DataSource | null = null;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
diagnosticDataSource = new DataSource({
|
|
157
|
+
...dataSourceOptions,
|
|
158
|
+
// Never re-run migrations or sync schema on the diagnostic connection.
|
|
159
|
+
migrationsRun: false,
|
|
160
|
+
synchronize: false,
|
|
161
|
+
// Keep the probe short so a genuinely-down DB doesn't slow the failing boot.
|
|
162
|
+
extra: {
|
|
163
|
+
...((dataSourceOptions as { extra?: Record<string, unknown> }).extra ||
|
|
164
|
+
{}),
|
|
165
|
+
connectionTimeoutMillis: 5000,
|
|
166
|
+
},
|
|
167
|
+
} as DataSourceOptions);
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
* If this fails, the original error was a connectivity problem (not a bad
|
|
171
|
+
* migration) — there is nothing meaningful to attribute, so we skip.
|
|
172
|
+
*/
|
|
173
|
+
await diagnosticDataSource.initialize();
|
|
174
|
+
|
|
175
|
+
const definedMigrationClasses: Array<new () => { name: string }> =
|
|
176
|
+
Array.isArray(dataSourceOptions.migrations)
|
|
177
|
+
? (dataSourceOptions.migrations as unknown as Array<
|
|
178
|
+
new () => { name: string }
|
|
179
|
+
>)
|
|
180
|
+
: [];
|
|
181
|
+
|
|
182
|
+
const definedNames: Array<string> = Array.from(
|
|
183
|
+
new Set(
|
|
184
|
+
definedMigrationClasses.map(
|
|
185
|
+
(MigrationClass: new () => { name: string }): string => {
|
|
186
|
+
return new MigrationClass().name;
|
|
187
|
+
},
|
|
188
|
+
),
|
|
189
|
+
),
|
|
190
|
+
).sort((a: string, b: string): number => {
|
|
191
|
+
return parseMigrationTimestamp(a) - parseMigrationTimestamp(b);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let appliedNames: Set<string> = new Set();
|
|
195
|
+
try {
|
|
196
|
+
const rows: Array<{ name: string }> = await diagnosticDataSource.query(
|
|
197
|
+
"SELECT name FROM migrations",
|
|
198
|
+
);
|
|
199
|
+
appliedNames = new Set(
|
|
200
|
+
rows.map((row: { name: string }): string => {
|
|
201
|
+
return row.name;
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
204
|
+
} catch {
|
|
205
|
+
// migrations table may not exist on a brand-new DB — treat as none applied.
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const firstPending: string | undefined = definedNames.find(
|
|
209
|
+
(name: string): boolean => {
|
|
210
|
+
return !appliedNames.has(name);
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* No pending schema migration means the connect() failure was not a pending
|
|
216
|
+
* migration failing (e.g. an entity-metadata error) — don't misattribute it.
|
|
217
|
+
*/
|
|
218
|
+
if (!firstPending) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await recordMigrationFailure(diagnosticDataSource, {
|
|
223
|
+
migrationName: firstPending,
|
|
224
|
+
migrationType: MigrationFailureType.PostgresSchema,
|
|
225
|
+
error: originalError,
|
|
226
|
+
});
|
|
227
|
+
} catch (err) {
|
|
228
|
+
// Best-effort diagnostics only — swallow everything.
|
|
229
|
+
logger.warn("Could not record Postgres schema migration failure.");
|
|
230
|
+
logger.warn(err);
|
|
231
|
+
} finally {
|
|
232
|
+
try {
|
|
233
|
+
if (diagnosticDataSource && diagnosticDataSource.isInitialized) {
|
|
234
|
+
await diagnosticDataSource.destroy();
|
|
235
|
+
}
|
|
236
|
+
} catch (destroyErr) {
|
|
237
|
+
logger.warn(destroyErr);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AppApiHostname } from "../EnvironmentConfig";
|
|
2
|
+
import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
|
|
3
|
+
import logger from "./Logger";
|
|
4
|
+
import Protocol from "../../Types/API/Protocol";
|
|
5
|
+
import Route from "../../Types/API/Route";
|
|
6
|
+
import URL from "../../Types/API/URL";
|
|
7
|
+
import API from "../../Utils/API";
|
|
8
|
+
import ObjectID from "../../Types/ObjectID";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Releases a provisioned incoming-call number on the call provider by delegating
|
|
12
|
+
* to the notification app's internal endpoint (the Common layer cannot reach the
|
|
13
|
+
* provider directly). Best-effort: failures are logged but never thrown, so a
|
|
14
|
+
* provider/network issue during cleanup does not block the parent delete.
|
|
15
|
+
*/
|
|
16
|
+
export default async function releaseIncomingCallPhoneNumber(data: {
|
|
17
|
+
projectCallSMSConfigId: ObjectID;
|
|
18
|
+
callProviderPhoneNumberId: string;
|
|
19
|
+
}): Promise<void> {
|
|
20
|
+
try {
|
|
21
|
+
await API.post({
|
|
22
|
+
url: new URL(
|
|
23
|
+
Protocol.HTTP,
|
|
24
|
+
AppApiHostname,
|
|
25
|
+
new Route("/api/notification/phone-number/internal/release"),
|
|
26
|
+
),
|
|
27
|
+
data: {
|
|
28
|
+
projectCallSMSConfigId: data.projectCallSMSConfigId.toString(),
|
|
29
|
+
callProviderPhoneNumberId: data.callProviderPhoneNumberId,
|
|
30
|
+
},
|
|
31
|
+
headers: {
|
|
32
|
+
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
} catch (err) {
|
|
36
|
+
logger.error(
|
|
37
|
+
"Failed to release incoming-call phone number on the provider during cleanup:",
|
|
38
|
+
);
|
|
39
|
+
logger.error(err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -49,6 +49,13 @@ export interface LLMUsage {
|
|
|
49
49
|
promptTokens: number;
|
|
50
50
|
completionTokens: number;
|
|
51
51
|
totalTokens: number;
|
|
52
|
+
/*
|
|
53
|
+
* Prompt-caching breakdown, when the provider reports it. cachedInputTokens
|
|
54
|
+
* are input tokens served from cache (billed at a large discount);
|
|
55
|
+
* cacheCreationTokens are input tokens written to the cache on this call.
|
|
56
|
+
*/
|
|
57
|
+
cachedInputTokens?: number | undefined;
|
|
58
|
+
cacheCreationTokens?: number | undefined;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
export interface LLMCompletionResponse {
|
|
@@ -237,6 +244,17 @@ export default class LLMService {
|
|
|
237
244
|
const toolCalls: Array<LLMToolCall> | undefined =
|
|
238
245
|
this.parseOpenAIToolCalls(message);
|
|
239
246
|
|
|
247
|
+
/*
|
|
248
|
+
* OpenAI (and Azure OpenAI) automatically cache a stable prompt prefix
|
|
249
|
+
* once it is long enough and report the cache hit under
|
|
250
|
+
* prompt_tokens_details.cached_tokens — surface it for cost visibility.
|
|
251
|
+
*/
|
|
252
|
+
const cachedTokens: number | undefined = usage
|
|
253
|
+
? ((usage["prompt_tokens_details"] as JSONObject | undefined)?.[
|
|
254
|
+
"cached_tokens"
|
|
255
|
+
] as number | undefined)
|
|
256
|
+
: undefined;
|
|
257
|
+
|
|
240
258
|
return {
|
|
241
259
|
content: (message["content"] as string) || "",
|
|
242
260
|
toolCalls: toolCalls,
|
|
@@ -246,6 +264,7 @@ export default class LLMService {
|
|
|
246
264
|
promptTokens: usage["prompt_tokens"] as number,
|
|
247
265
|
completionTokens: usage["completion_tokens"] as number,
|
|
248
266
|
totalTokens: usage["total_tokens"] as number,
|
|
267
|
+
cachedInputTokens: cachedTokens || undefined,
|
|
249
268
|
}
|
|
250
269
|
: undefined,
|
|
251
270
|
};
|
|
@@ -565,6 +584,32 @@ export default class LLMService {
|
|
|
565
584
|
continue;
|
|
566
585
|
}
|
|
567
586
|
|
|
587
|
+
/*
|
|
588
|
+
* Anthropic requires strictly alternating user/assistant turns and
|
|
589
|
+
* returns a 400 on two consecutive same-role messages. The agent loop
|
|
590
|
+
* can legitimately emit back-to-back user turns (e.g. a tool_result
|
|
591
|
+
* user message immediately followed by the "budget exhausted, answer
|
|
592
|
+
* now" nudge), so coalesce a run of same-role messages into one instead
|
|
593
|
+
* of failing the whole request.
|
|
594
|
+
*/
|
|
595
|
+
const previousMessage: JSONObject | undefined =
|
|
596
|
+
anthropicMessages[anthropicMessages.length - 1];
|
|
597
|
+
|
|
598
|
+
if (previousMessage && previousMessage["role"] === msg.role) {
|
|
599
|
+
if (typeof previousMessage["content"] === "string") {
|
|
600
|
+
previousMessage["content"] =
|
|
601
|
+
`${previousMessage["content"] as string}\n\n${msg.content}`;
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (Array.isArray(previousMessage["content"])) {
|
|
605
|
+
(previousMessage["content"] as Array<JSONObject>).push({
|
|
606
|
+
type: "text",
|
|
607
|
+
text: msg.content,
|
|
608
|
+
});
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
568
613
|
anthropicMessages.push({
|
|
569
614
|
role: msg.role,
|
|
570
615
|
content: msg.content,
|
|
@@ -602,18 +647,43 @@ export default class LLMService {
|
|
|
602
647
|
max_tokens: request.maxTokens || LLMService.ANTHROPIC_DEFAULT_MAX_TOKENS,
|
|
603
648
|
};
|
|
604
649
|
|
|
650
|
+
/*
|
|
651
|
+
* Prompt caching. The system prompt and tool definitions are the large,
|
|
652
|
+
* stable prefix re-sent on every turn of the agent loop, so caching them is
|
|
653
|
+
* the biggest single cost + latency lever (cached input is billed at ~10%).
|
|
654
|
+
* An ephemeral cache_control breakpoint on the system block and on the LAST
|
|
655
|
+
* tool caches the whole system + tools prefix. cache_control is GA under
|
|
656
|
+
* anthropic-version 2023-06-01, so no beta header is required.
|
|
657
|
+
*/
|
|
605
658
|
if (systemMessage) {
|
|
606
|
-
requestData["system"] =
|
|
659
|
+
requestData["system"] = [
|
|
660
|
+
{
|
|
661
|
+
type: "text",
|
|
662
|
+
text: systemMessage,
|
|
663
|
+
cache_control: { type: "ephemeral" },
|
|
664
|
+
},
|
|
665
|
+
];
|
|
607
666
|
}
|
|
608
667
|
|
|
609
668
|
if (request.tools && request.tools.length > 0) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
669
|
+
const anthropicTools: Array<JSONObject> = request.tools.map(
|
|
670
|
+
(tool: LLMToolDefinition) => {
|
|
671
|
+
return {
|
|
672
|
+
name: tool.name,
|
|
673
|
+
description: tool.description,
|
|
674
|
+
input_schema: tool.inputSchema,
|
|
675
|
+
};
|
|
676
|
+
},
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
// A breakpoint on the last tool caches the entire tools block before it.
|
|
680
|
+
const lastTool: JSONObject | undefined =
|
|
681
|
+
anthropicTools[anthropicTools.length - 1];
|
|
682
|
+
if (lastTool) {
|
|
683
|
+
lastTool["cache_control"] = { type: "ephemeral" };
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
requestData["tools"] = anthropicTools;
|
|
617
687
|
}
|
|
618
688
|
|
|
619
689
|
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
@@ -685,10 +755,21 @@ export default class LLMService {
|
|
|
685
755
|
stopReason: jsonData["stop_reason"] === "tool_use" ? "tool_use" : "stop",
|
|
686
756
|
usage: usage
|
|
687
757
|
? {
|
|
688
|
-
promptTokens: usage["input_tokens"] as number,
|
|
689
|
-
completionTokens: usage["output_tokens"] as number,
|
|
758
|
+
promptTokens: (usage["input_tokens"] as number) || 0,
|
|
759
|
+
completionTokens: (usage["output_tokens"] as number) || 0,
|
|
760
|
+
/*
|
|
761
|
+
* Anthropic reports cache-read and cache-creation input tokens
|
|
762
|
+
* separately from input_tokens. Surface them and fold them into
|
|
763
|
+
* totalTokens so the logged total reflects the full billable input.
|
|
764
|
+
*/
|
|
765
|
+
cachedInputTokens:
|
|
766
|
+
(usage["cache_read_input_tokens"] as number) || undefined,
|
|
767
|
+
cacheCreationTokens:
|
|
768
|
+
(usage["cache_creation_input_tokens"] as number) || undefined,
|
|
690
769
|
totalTokens:
|
|
691
770
|
((usage["input_tokens"] as number) || 0) +
|
|
771
|
+
((usage["cache_read_input_tokens"] as number) || 0) +
|
|
772
|
+
((usage["cache_creation_input_tokens"] as number) || 0) +
|
|
692
773
|
((usage["output_tokens"] as number) || 0),
|
|
693
774
|
}
|
|
694
775
|
: undefined,
|
|
@@ -812,11 +893,29 @@ export default class LLMService {
|
|
|
812
893
|
});
|
|
813
894
|
}
|
|
814
895
|
|
|
896
|
+
/*
|
|
897
|
+
* Ollama reports token counts on the final /api/chat response as
|
|
898
|
+
* prompt_eval_count (input) and eval_count (output). Populate usage from
|
|
899
|
+
* them so LlmLog, the AI dashboards and (costed self-hosted Ollama)
|
|
900
|
+
* billing are not silently blind to token spend.
|
|
901
|
+
*/
|
|
902
|
+
const ollamaPromptTokens: number =
|
|
903
|
+
(jsonData["prompt_eval_count"] as number) || 0;
|
|
904
|
+
const ollamaCompletionTokens: number =
|
|
905
|
+
(jsonData["eval_count"] as number) || 0;
|
|
906
|
+
|
|
815
907
|
return {
|
|
816
908
|
content: (message["content"] as string) || "",
|
|
817
909
|
toolCalls: toolCalls,
|
|
818
910
|
stopReason: toolCalls && toolCalls.length > 0 ? "tool_use" : "stop",
|
|
819
|
-
usage:
|
|
911
|
+
usage:
|
|
912
|
+
ollamaPromptTokens || ollamaCompletionTokens
|
|
913
|
+
? {
|
|
914
|
+
promptTokens: ollamaPromptTokens,
|
|
915
|
+
completionTokens: ollamaCompletionTokens,
|
|
916
|
+
totalTokens: ollamaPromptTokens + ollamaCompletionTokens,
|
|
917
|
+
}
|
|
918
|
+
: undefined,
|
|
820
919
|
};
|
|
821
920
|
}
|
|
822
921
|
}
|
|
@@ -141,31 +141,34 @@ function parseUnixNanoToDate(
|
|
|
141
141
|
value: string | number | undefined,
|
|
142
142
|
context: string,
|
|
143
143
|
): Date {
|
|
144
|
-
let numericValue: number = OneUptimeDate.getCurrentDateAsUnixNano();
|
|
145
|
-
|
|
146
144
|
if (value !== undefined && value !== null) {
|
|
147
145
|
try {
|
|
148
146
|
if (typeof value === "string") {
|
|
149
|
-
const
|
|
150
|
-
if (isNaN(
|
|
147
|
+
const trimmed: string = value.trim();
|
|
148
|
+
if (trimmed === "" || isNaN(Number(trimmed))) {
|
|
151
149
|
throw new Error(`Invalid timestamp string: ${value}`);
|
|
152
150
|
}
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
/*
|
|
152
|
+
* Hand the raw nanosecond string to fromUnixNano so it can divide
|
|
153
|
+
* with BigInt — nanosecond epochs exceed Number.MAX_SAFE_INTEGER, so
|
|
154
|
+
* parsing to a float here would drop up to a full millisecond.
|
|
155
|
+
*/
|
|
156
|
+
return OneUptimeDate.fromUnixNano(trimmed);
|
|
157
|
+
}
|
|
158
|
+
if (typeof value === "number") {
|
|
155
159
|
if (!Number.isFinite(value)) {
|
|
156
160
|
throw new Error(`Invalid timestamp number: ${value}`);
|
|
157
161
|
}
|
|
158
|
-
|
|
162
|
+
return OneUptimeDate.fromUnixNano(value);
|
|
159
163
|
}
|
|
160
164
|
} catch (error) {
|
|
161
165
|
logger.warn(
|
|
162
166
|
`Error processing ${context}: ${error instanceof Error ? error.message : String(error)}, using current time`,
|
|
163
167
|
);
|
|
164
|
-
numericValue = OneUptimeDate.getCurrentDateAsUnixNano();
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
|
|
168
|
-
return OneUptimeDate.
|
|
171
|
+
return OneUptimeDate.getCurrentDate();
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
// Same trim-or-null read contract as OtelIngestBaseService.getStringAttribute.
|
|
@@ -242,31 +242,34 @@ function parseUnixNanoToDate(
|
|
|
242
242
|
value: string | number | undefined,
|
|
243
243
|
context: string,
|
|
244
244
|
): Date {
|
|
245
|
-
let numericValue: number = OneUptimeDate.getCurrentDateAsUnixNano();
|
|
246
|
-
|
|
247
245
|
if (value !== undefined && value !== null) {
|
|
248
246
|
try {
|
|
249
247
|
if (typeof value === "string") {
|
|
250
|
-
const
|
|
251
|
-
if (isNaN(
|
|
248
|
+
const trimmed: string = value.trim();
|
|
249
|
+
if (trimmed === "" || isNaN(Number(trimmed))) {
|
|
252
250
|
throw new Error(`Invalid timestamp string: ${value}`);
|
|
253
251
|
}
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
/*
|
|
253
|
+
* Hand the raw nanosecond string to fromUnixNano so it can divide
|
|
254
|
+
* with BigInt — nanosecond epochs exceed Number.MAX_SAFE_INTEGER, so
|
|
255
|
+
* parsing to a float here would drop up to a full millisecond.
|
|
256
|
+
*/
|
|
257
|
+
return OneUptimeDate.fromUnixNano(trimmed);
|
|
258
|
+
}
|
|
259
|
+
if (typeof value === "number") {
|
|
256
260
|
if (!Number.isFinite(value)) {
|
|
257
261
|
throw new Error(`Invalid timestamp number: ${value}`);
|
|
258
262
|
}
|
|
259
|
-
|
|
263
|
+
return OneUptimeDate.fromUnixNano(value);
|
|
260
264
|
}
|
|
261
265
|
} catch (error) {
|
|
262
266
|
logger.warn(
|
|
263
267
|
`Error processing ${context}: ${error instanceof Error ? error.message : String(error)}, using current time`,
|
|
264
268
|
);
|
|
265
|
-
numericValue = OneUptimeDate.getCurrentDateAsUnixNano();
|
|
266
269
|
}
|
|
267
270
|
}
|
|
268
271
|
|
|
269
|
-
return OneUptimeDate.
|
|
272
|
+
return OneUptimeDate.getCurrentDate();
|
|
270
273
|
}
|
|
271
274
|
|
|
272
275
|
// Same trim-or-null read contract as OtelIngestBaseService.getStringAttribute.
|
|
@@ -103,6 +103,7 @@ jest.mock("../../../Server/Services/ProjectService", () => {
|
|
|
103
103
|
|
|
104
104
|
jest.mock("../../../Server/EnvironmentConfig", () => {
|
|
105
105
|
return {
|
|
106
|
+
...jest.requireActual("../../../Server/EnvironmentConfig"),
|
|
106
107
|
IsBillingEnabled: true,
|
|
107
108
|
LogLevel: "INFO", // Use string literal instead of ConfigLogLevel.INFO
|
|
108
109
|
DisableTelemetry: true,
|
|
@@ -234,14 +234,6 @@ describe("AnalyticsDatabaseService", () => {
|
|
|
234
234
|
jest.spyOn(logger, "error").mockImplementation(() => {
|
|
235
235
|
return undefined!;
|
|
236
236
|
});
|
|
237
|
-
|
|
238
|
-
/*
|
|
239
|
-
* The base getException method is async and throws without await in the
|
|
240
|
-
* catch block, creating unhandled rejections. Override to throw synchronously.
|
|
241
|
-
*/
|
|
242
|
-
(service as any).getException = (error: Error): never => {
|
|
243
|
-
throw error;
|
|
244
|
-
};
|
|
245
237
|
});
|
|
246
238
|
|
|
247
239
|
afterEach(() => {
|