@oneuptime/common 11.5.4 → 11.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/AIAgentTaskPullRequest.ts +56 -45
- package/Models/DatabaseModels/AIInsight.ts +748 -0
- package/Models/DatabaseModels/AIRun.ts +262 -0
- package/Models/DatabaseModels/CodeRepository.ts +42 -0
- package/Models/DatabaseModels/GlobalConfig.ts +105 -0
- package/Models/DatabaseModels/Index.ts +4 -8
- package/Models/DatabaseModels/InstanceHealthLog.ts +277 -0
- package/Models/DatabaseModels/LlmLog.ts +33 -0
- package/Models/DatabaseModels/Project.ts +123 -6
- package/Models/DatabaseModels/Runbook.ts +1 -1
- package/Server/API/AIAgentDataAPI.ts +802 -140
- package/Server/API/AIAgentTaskAPI.ts +132 -69
- package/Server/API/AIAgentTaskLogAPI.ts +65 -41
- package/Server/API/AIAgentTaskPullRequestAPI.ts +41 -0
- package/Server/API/AIInsightAPI.ts +220 -0
- package/Server/API/AIInvestigationAPI.ts +363 -1
- package/Server/API/CodeFixRunAPI.ts +251 -0
- package/Server/API/GitHubAPI.ts +246 -3
- package/Server/API/TelemetryExceptionAPI.ts +193 -48
- package/Server/EnvironmentConfig.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.ts +73 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.ts +37 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.ts +75 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.ts +37 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.ts +203 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.ts +163 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +30 -0
- package/Server/Infrastructure/Queue.ts +82 -4
- package/Server/Infrastructure/Semaphore.ts +62 -1
- package/Server/Services/AIAgentService.ts +32 -0
- package/Server/Services/AIAgentTaskPullRequestService.ts +117 -0
- package/Server/Services/AIInsightService.ts +174 -0
- package/Server/Services/AIRunEventService.ts +63 -0
- package/Server/Services/AIRunService.ts +259 -1
- package/Server/Services/AIService.ts +249 -7
- package/Server/Services/AlertService.ts +4 -4
- package/Server/Services/CodeRepositoryService.ts +209 -0
- package/Server/Services/GlobalConfigService.ts +148 -0
- package/Server/Services/IncidentService.ts +183 -38
- package/Server/Services/IncidentStateTimelineService.ts +24 -4
- package/Server/Services/Index.ts +4 -4
- package/Server/Services/{AIAgentTaskLogService.ts → InstanceHealthLogService.ts} +1 -1
- package/Server/Services/LlmLogService.ts +27 -0
- package/Server/Services/LlmProviderService.ts +108 -0
- package/Server/Services/MetricBaselineService.ts +123 -0
- package/Server/Services/MonitorService.ts +15 -0
- package/Server/Services/TelemetryExceptionService.ts +323 -116
- package/Server/Services/TraceAggregationService.ts +176 -0
- package/Server/Types/Workflow/ComponentCode.ts +6 -0
- package/Server/Types/Workflow/Components/AI/GenerateText.ts +326 -0
- package/Server/Types/Workflow/Components/Index.ts +2 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +1 -1
- package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +71 -0
- package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +243 -0
- package/Server/Utils/AI/CodeFix/CodeFixRunQueue.ts +131 -0
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +148 -0
- package/Server/Utils/AI/CodeFix/OpenPullRequestCap.ts +117 -0
- package/Server/Utils/AI/Eval/EvalCorpus.ts +369 -0
- package/Server/Utils/AI/Eval/EvalScores.ts +172 -0
- package/Server/Utils/AI/Eval/ReplayInvestigation.ts +87 -0
- package/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.ts +676 -0
- package/Server/Utils/AI/{Sentinel/SentinelInvestigationEngine.ts → SRE/AIInvestigationEngine.ts} +58 -37
- package/Server/Utils/AI/{Sentinel/SentinelMemory.ts → SRE/AIMemory.ts} +3 -3
- package/Server/Utils/AI/{Sentinel → SRE}/AlertInvestigationRunner.ts +50 -20
- package/Server/Utils/AI/SRE/ConfidenceSignal.ts +293 -0
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +115 -0
- package/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.ts +223 -0
- package/Server/Utils/AI/{Sentinel → SRE}/IncidentInvestigationRunner.ts +71 -21
- package/Server/Utils/AI/{Sentinel → SRE}/IncidentPostmortemRunner.ts +8 -8
- package/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.ts +364 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +317 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/Index.ts +27 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.ts +221 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +238 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.ts +521 -0
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +242 -0
- package/Server/Utils/AI/SRE/Insights/InsightScanner.ts +290 -0
- package/Server/Utils/AI/SRE/Insights/InsightStore.ts +283 -0
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +242 -0
- package/Server/Utils/AI/SRE/Insights/Triage.ts +162 -0
- package/Server/Utils/AI/SRE/Insights/Types.ts +49 -0
- package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +212 -0
- package/Server/Utils/AI/SRE/InvestigationGrader.ts +282 -0
- package/Server/Utils/AI/{Sentinel → SRE}/InvestigationQueue.ts +114 -19
- package/Server/Utils/AI/{Sentinel → SRE}/README.md +4 -4
- package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +172 -0
- package/Server/Utils/AI/Toolbox/{SentinelActionTools.ts → AIActionTools.ts} +22 -1
- package/Server/Utils/AI/Toolbox/Index.ts +2 -2
- package/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.ts +526 -0
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +319 -1
- package/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.ts +221 -0
- package/Server/Utils/CodeRepository/StackTraceRepoResolver.ts +571 -0
- package/Server/Utils/Execute.ts +2 -1
- package/Server/Utils/LLM/LLMService.ts +160 -30
- package/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.ts +152 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +29 -0
- package/Tests/Server/Infrastructure/Queue.test.ts +227 -0
- package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +159 -0
- package/Tests/Server/Services/AIAgentTaskPullRequestOutcomeStats.test.ts +154 -0
- package/Tests/Server/Services/AIInsightService.test.ts +324 -0
- package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +401 -0
- package/Tests/Server/Services/AIRunHumanVerdict.test.ts +161 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +95 -5
- package/Tests/Server/Services/AIServiceProjectAccess.test.ts +259 -0
- package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +249 -0
- package/Tests/Server/Services/FixPerformanceTaskTrigger.test.ts +274 -0
- package/Tests/Server/Services/GlobalConfigService.test.ts +80 -0
- package/Tests/Server/Services/IncidentInternalNoteAnnouncement.test.ts +1 -1
- package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +313 -0
- package/Tests/Server/Services/LlmProviderProjectOwned.test.ts +132 -0
- package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +405 -0
- package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +322 -0
- package/Tests/Server/Services/TraceServiceLatencyProfile.test.ts +278 -0
- package/Tests/Server/Types/Workflow/Components/AIGenerateText.test.ts +722 -0
- package/Tests/Server/Utils/AI/{SentinelAlertGating.test.ts → AIAlertGating.test.ts} +19 -19
- package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +362 -0
- package/Tests/Server/Utils/AI/{SentinelInvestigationQueue.test.ts → AIInvestigationQueue.test.ts} +19 -19
- package/Tests/Server/Utils/AI/CodeAgentWorkspaceGuard.test.ts +138 -0
- package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +335 -0
- package/Tests/Server/Utils/AI/CodeFixRunQueue.test.ts +134 -0
- package/Tests/Server/Utils/AI/EvalCorpus.test.ts +209 -0
- package/Tests/Server/Utils/AI/EvalScores.test.ts +343 -0
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +218 -0
- package/Tests/Server/Utils/AI/Insights/ErrorLogSpikeDetector.test.ts +437 -0
- package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +287 -0
- package/Tests/Server/Utils/AI/Insights/InsightDetectorsIndex.test.ts +34 -0
- package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +572 -0
- package/Tests/Server/Utils/AI/Insights/InsightNeverThrowsHardening.test.ts +344 -0
- package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +720 -0
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +467 -0
- package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +370 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +210 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +221 -0
- package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +328 -0
- package/Tests/Server/Utils/AI/Insights/MetricBaselineDrift.test.ts +182 -0
- package/Tests/Server/Utils/AI/Insights/MetricDriftDetector.test.ts +280 -0
- package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +259 -0
- package/Tests/Server/Utils/AI/Insights/TraceLatencyRegressionDetector.test.ts +770 -0
- package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +343 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +307 -0
- package/Tests/Server/Utils/AI/OpenPullRequestCap.test.ts +170 -0
- package/Tests/Server/Utils/AI/SpanTreeAnalyzer.test.ts +559 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.test.ts +158 -0
- package/Tests/Server/Utils/GitHubCheckRunsConclusion.test.ts +100 -0
- package/Tests/Server/Utils/GitHubPullRequestStateMapping.test.ts +50 -0
- package/Tests/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.test.ts +266 -0
- package/Tests/Server/Utils/ServiceRepoLinkSuggester.test.ts +167 -0
- package/Tests/Server/Utils/StackTraceRepoResolver.test.ts +527 -0
- package/Tests/Types/AI/AIChatPermissionMode.test.ts +112 -0
- package/Tests/Types/AI/CodeFixTaskType.test.ts +152 -0
- package/Tests/Types/AI/FixPullRequestCiStatus.test.ts +181 -0
- package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +110 -0
- package/Tests/Types/Monitor/SqlDatabaseType.test.ts +55 -0
- package/Tests/Types/Workflow/AIGenerateTextMetadata.test.ts +180 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +168 -0
- package/Tests/UI/Utils/TableColumnsToCsv.test.ts +523 -0
- package/Types/AI/AIChatTypes.ts +8 -0
- package/Types/AI/AIInsightEvidence.ts +77 -0
- package/Types/AI/AIInsightHumanVerdict.ts +15 -0
- package/Types/AI/AIInsightSeverity.ts +13 -0
- package/Types/AI/AIInsightStatus.ts +38 -0
- package/Types/AI/AIInsightType.ts +41 -0
- package/Types/AI/AIRunAutoGrade.ts +18 -0
- package/Types/AI/AIRunEventType.ts +5 -0
- package/Types/AI/AIRunHumanVerdict.ts +17 -0
- package/Types/AI/AIRunType.ts +6 -0
- package/Types/AI/CodeFixTaskContext.ts +88 -0
- package/Types/AI/CodeFixTaskType.ts +132 -0
- package/Types/AI/FixPullRequestCiStatus.ts +132 -0
- package/Types/BaseDatabase/AggregationIntervalUtil.ts +67 -0
- package/Types/Incident/IncidentMetricType.ts +7 -0
- package/Types/Monitor/CriteriaFilter.ts +8 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +38 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +141 -0
- package/Types/Monitor/MonitorType.ts +17 -0
- package/Types/Monitor/SqlDatabaseType.ts +49 -0
- package/Types/Monitor/SqlMonitor/SqlMonitorResponse.ts +28 -0
- package/Types/Permission.ts +11 -95
- package/Types/Probe/ProbeMonitorResponse.ts +2 -0
- package/Types/Runbook/RunbookStep.ts +26 -2
- package/Types/Runbook/RunbookStepType.ts +1 -0
- package/Types/Workflow/Component.ts +13 -0
- package/Types/Workflow/ComponentID.ts +1 -0
- package/Types/Workflow/Components/AI.ts +148 -0
- package/Types/Workflow/Components.ts +8 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +1 -1
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +11 -0
- package/UI/Components/MoreMenu/MoreMenu.tsx +1 -1
- package/UI/Components/Table/Table.tsx +38 -2
- package/UI/Utils/TableColumnsToCsv.ts +385 -0
- package/Utils/Monitor/MonitorMetricType.ts +1 -0
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +59 -45
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIInsight.js +795 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +274 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +43 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +110 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -8
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InstanceHealthLog.js +304 -0
- package/build/dist/Models/DatabaseModels/InstanceHealthLog.js.map +1 -0
- package/build/dist/Models/DatabaseModels/LlmLog.js +35 -0
- package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +127 -6
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Runbook.js +1 -1
- package/build/dist/Models/DatabaseModels/Runbook.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +568 -85
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskAPI.js +100 -44
- package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskLogAPI.js +49 -25
- package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js +27 -0
- package/build/dist/Server/API/AIAgentTaskPullRequestAPI.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +140 -0
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -0
- package/build/dist/Server/API/AIInvestigationAPI.js +257 -1
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/CodeFixRunAPI.js +181 -0
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -0
- package/build/dist/Server/API/GitHubAPI.js +164 -2
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +148 -43
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +1 -1
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783943300000-DropServiceCodeRepository.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783947444597-CodeFixRunsOnAIRun.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783950962813-AddCodeFixTaskType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783954040984-AddInstrumentationFixTasksFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783957160597-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783958542237-AddTaskContextToAIRun.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783965945957-AddInvestigationVerdictAndGrade.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619301-AddFixGuardrailColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783970619302-DropLegacyAIAgentTaskTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783977781677-AddCiStatusToFixPullRequests.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783990000000-AddCompletionTokensToLlmLog.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274993-AddSentinelInsight.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784010274994-AddSentinelInsightFlags.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.js +125 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784030612266-RenameSentinelToAI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.js +62 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784033837629-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +73 -3
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +44 -1
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Services/AIAgentService.js +29 -0
- package/build/dist/Server/Services/AIAgentService.js.map +1 -1
- package/build/dist/Server/Services/AIAgentTaskPullRequestService.js +78 -0
- package/build/dist/Server/Services/AIAgentTaskPullRequestService.js.map +1 -1
- package/build/dist/Server/Services/AIInsightService.js +164 -0
- package/build/dist/Server/Services/AIInsightService.js.map +1 -0
- package/build/dist/Server/Services/AIRunEventService.js +49 -0
- package/build/dist/Server/Services/AIRunEventService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +221 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +198 -11
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +4 -4
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/CodeRepositoryService.js +180 -0
- package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +84 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +149 -37
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +24 -4
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -4
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/{AIAgentTaskLogService.js → InstanceHealthLogService.js} +2 -2
- package/build/dist/Server/Services/InstanceHealthLogService.js.map +1 -0
- package/build/dist/Server/Services/LlmLogService.js +23 -0
- package/build/dist/Server/Services/LlmLogService.js.map +1 -1
- package/build/dist/Server/Services/LlmProviderService.js +96 -0
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/MetricBaselineService.js +65 -0
- package/build/dist/Server/Services/MetricBaselineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +9 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +243 -82
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +124 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/ComponentCode.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/AI/GenerateText.js +240 -0
- package/build/dist/Server/Types/Workflow/Components/AI/GenerateText.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/Index.js +2 -0
- package/build/dist/Server/Types/Workflow/Components/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +48 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +174 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js +126 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +131 -0
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/OpenPullRequestCap.js +99 -0
- package/build/dist/Server/Utils/AI/CodeFix/OpenPullRequestCap.js.map +1 -0
- package/build/dist/Server/Utils/AI/Eval/EvalCorpus.js +245 -0
- package/build/dist/Server/Utils/AI/Eval/EvalCorpus.js.map +1 -0
- package/build/dist/Server/Utils/AI/Eval/EvalScores.js +83 -0
- package/build/dist/Server/Utils/AI/Eval/EvalScores.js.map +1 -0
- package/build/dist/Server/Utils/AI/Eval/ReplayInvestigation.js +12 -0
- package/build/dist/Server/Utils/AI/Eval/ReplayInvestigation.js.map +1 -0
- package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js +439 -0
- package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel/SentinelInvestigationEngine.js → SRE/AIInvestigationEngine.js} +47 -31
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel/SentinelMemory.js → SRE/AIMemory.js} +5 -5
- package/build/dist/Server/Utils/AI/SRE/AIMemory.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel → SRE}/AlertInvestigationRunner.js +42 -19
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +226 -0
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +100 -0
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.js +174 -0
- package/build/dist/Server/Utils/AI/SRE/FixPerformanceTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel → SRE}/IncidentInvestigationRunner.js +60 -22
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel → SRE}/IncidentPostmortemRunner.js +9 -9
- package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.js +268 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ErrorLogSpikeDetector.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +226 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/Index.js +26 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/Index.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.js +159 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/MetricDriftDetector.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +177 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.js +384 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/TraceLatencyRegressionDetector.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js +180 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js +269 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +231 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +206 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js +121 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Types.js +2 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Types.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +148 -0
- package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +231 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -0
- package/build/dist/Server/Utils/AI/{Sentinel → SRE}/InvestigationQueue.js +102 -23
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +167 -0
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/{SentinelActionTools.js → AIActionTools.js} +18 -2
- package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -2
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js +301 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +240 -2
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.js +127 -0
- package/build/dist/Server/Utils/CodeRepository/ServiceRepoLinkSuggester.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js +336 -0
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js.map +1 -0
- package/build/dist/Server/Utils/Execute.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +125 -25
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.js +120 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SqlMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Types/AI/AIInsightEvidence.js +2 -0
- package/build/dist/Types/AI/AIInsightEvidence.js.map +1 -0
- package/build/dist/Types/AI/AIInsightHumanVerdict.js +16 -0
- package/build/dist/Types/AI/AIInsightHumanVerdict.js.map +1 -0
- package/build/dist/Types/AI/AIInsightSeverity.js +14 -0
- package/build/dist/Types/AI/AIInsightSeverity.js.map +1 -0
- package/build/dist/Types/AI/AIInsightStatus.js +36 -0
- package/build/dist/Types/AI/AIInsightStatus.js.map +1 -0
- package/build/dist/Types/AI/AIInsightType.js +42 -0
- package/build/dist/Types/AI/AIInsightType.js.map +1 -0
- package/build/dist/Types/AI/AIRunAutoGrade.js +19 -0
- package/build/dist/Types/AI/AIRunAutoGrade.js.map +1 -0
- package/build/dist/Types/AI/AIRunEventType.js +5 -0
- package/build/dist/Types/AI/AIRunEventType.js.map +1 -1
- package/build/dist/Types/AI/AIRunHumanVerdict.js +18 -0
- package/build/dist/Types/AI/AIRunHumanVerdict.js.map +1 -0
- package/build/dist/Types/AI/AIRunType.js +6 -0
- package/build/dist/Types/AI/AIRunType.js.map +1 -1
- package/build/dist/Types/AI/CodeFixTaskContext.js +29 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -0
- package/build/dist/Types/AI/CodeFixTaskType.js +122 -0
- package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -0
- package/build/dist/Types/AI/FixPullRequestCiStatus.js +102 -0
- package/build/dist/Types/AI/FixPullRequestCiStatus.js.map +1 -0
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +55 -0
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
- package/build/dist/Types/Incident/IncidentMetricType.js +7 -0
- package/build/dist/Types/Incident/IncidentMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +7 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +28 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +93 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +15 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SqlDatabaseType.js +47 -0
- package/build/dist/Types/Monitor/SqlDatabaseType.js.map +1 -0
- package/build/dist/Types/Monitor/SqlMonitor/SqlMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/SqlMonitor/SqlMonitorResponse.js.map +1 -0
- package/build/dist/Types/Permission.js +10 -84
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Runbook/RunbookStepType.js +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Workflow/ComponentID.js +1 -0
- package/build/dist/Types/Workflow/ComponentID.js.map +1 -1
- package/build/dist/Types/Workflow/Components/AI.js +135 -0
- package/build/dist/Types/Workflow/Components/AI.js.map +1 -0
- package/build/dist/Types/Workflow/Components.js +7 -0
- package/build/dist/Types/Workflow/Components.js.map +1 -1
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -1
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +9 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +1 -1
- package/build/dist/UI/Components/Table/Table.js +28 -2
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Utils/TableColumnsToCsv.js +291 -0
- package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js +1 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/package.json +1 -1
- package/Models/DatabaseModels/AIAgentTask.ts +0 -660
- package/Models/DatabaseModels/AIAgentTaskLog.ts +0 -426
- package/Models/DatabaseModels/AIAgentTaskTelemetryException.ts +0 -399
- package/Models/DatabaseModels/ServiceCodeRepository.ts +0 -647
- package/Server/Services/AIAgentTaskService.ts +0 -240
- package/Server/Services/AIAgentTaskTelemetryExceptionService.ts +0 -39
- package/Server/Services/ServiceCodeRepositoryService.ts +0 -55
- package/Tests/Server/Services/AIAgentTaskServiceClaim.test.ts +0 -146
- package/Types/AI/AIAgentTaskMetadata.ts +0 -25
- package/Types/AI/AIAgentTaskType.ts +0 -40
- package/build/dist/Models/DatabaseModels/AIAgentTask.js +0 -691
- package/build/dist/Models/DatabaseModels/AIAgentTask.js.map +0 -1
- package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js +0 -447
- package/build/dist/Models/DatabaseModels/AIAgentTaskLog.js.map +0 -1
- package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js +0 -415
- package/build/dist/Models/DatabaseModels/AIAgentTaskTelemetryException.js.map +0 -1
- package/build/dist/Models/DatabaseModels/ServiceCodeRepository.js +0 -665
- package/build/dist/Models/DatabaseModels/ServiceCodeRepository.js.map +0 -1
- package/build/dist/Server/Services/AIAgentTaskLogService.js.map +0 -1
- package/build/dist/Server/Services/AIAgentTaskService.js +0 -217
- package/build/dist/Server/Services/AIAgentTaskService.js.map +0 -1
- package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js +0 -36
- package/build/dist/Server/Services/AIAgentTaskTelemetryExceptionService.js.map +0 -1
- package/build/dist/Server/Services/ServiceCodeRepositoryService.js +0 -54
- package/build/dist/Server/Services/ServiceCodeRepositoryService.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/IncidentPostmortemRunner.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +0 -1
- package/build/dist/Server/Utils/AI/Sentinel/SentinelMemory.js.map +0 -1
- package/build/dist/Server/Utils/AI/Toolbox/SentinelActionTools.js.map +0 -1
- package/build/dist/Types/AI/AIAgentTaskMetadata.js +0 -6
- package/build/dist/Types/AI/AIAgentTaskMetadata.js.map +0 -1
- package/build/dist/Types/AI/AIAgentTaskType.js +0 -29
- package/build/dist/Types/AI/AIAgentTaskType.js.map +0 -1
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import AIRunService from "../../../Server/Services/AIRunService";
|
|
2
|
+
import AIRun from "../../../Models/DatabaseModels/AIRun";
|
|
3
|
+
import AIRunStatus from "../../../Types/AI/AIRunStatus";
|
|
4
|
+
import CodeFixTaskType from "../../../Types/AI/CodeFixTaskType";
|
|
5
|
+
import CodeFixTaskContext from "../../../Types/AI/CodeFixTaskContext";
|
|
6
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
7
|
+
import { describe, expect, test, afterEach } from "@jest/globals";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* The code-fix claim behind POST /ai-agent-task/get-pending-task: the
|
|
11
|
+
* oldest Queued CodeFix run is claimed with the same status+attemptCount
|
|
12
|
+
* guarded CAS the investigation queue uses, so concurrent agent workers can
|
|
13
|
+
* never receive the same run. These tests mock findOneBy /
|
|
14
|
+
* attemptStatusTransition (the AIInvestigationQueue test idiom) and
|
|
15
|
+
* lock in the claim invariants.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
function fakeQueuedRun(data?: {
|
|
19
|
+
exceptionId?: ObjectID | null;
|
|
20
|
+
attemptCount?: number;
|
|
21
|
+
codeFixTaskType?: CodeFixTaskType;
|
|
22
|
+
incidentId?: ObjectID;
|
|
23
|
+
alertId?: ObjectID;
|
|
24
|
+
taskContext?: CodeFixTaskContext;
|
|
25
|
+
}): AIRun {
|
|
26
|
+
return {
|
|
27
|
+
id: ObjectID.generate(),
|
|
28
|
+
projectId: ObjectID.generate(),
|
|
29
|
+
triggeredByTelemetryExceptionId:
|
|
30
|
+
data?.exceptionId === null
|
|
31
|
+
? undefined
|
|
32
|
+
: data?.exceptionId || ObjectID.generate(),
|
|
33
|
+
triggeredByIncidentId: data?.incidentId,
|
|
34
|
+
triggeredByAlertId: data?.alertId,
|
|
35
|
+
attemptCount: data?.attemptCount || 0,
|
|
36
|
+
codeFixTaskType: data?.codeFixTaskType,
|
|
37
|
+
taskContext: data?.taskContext,
|
|
38
|
+
} as unknown as AIRun;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("AIRunService.claimNextQueuedCodeFixRun", () => {
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
jest.restoreAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns null when no queued code-fix run exists — no CAS attempted", async () => {
|
|
47
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(null);
|
|
48
|
+
const transition: jest.SpyInstance = jest.spyOn(
|
|
49
|
+
AIRunService,
|
|
50
|
+
"attemptStatusTransition",
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
54
|
+
aiAgentId: ObjectID.generate(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(claimed).toBeNull();
|
|
58
|
+
expect(transition).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("a won claim transitions Queued -> Running with heartbeat, agent id and attemptCount+1", async () => {
|
|
62
|
+
const run: AIRun = fakeQueuedRun();
|
|
63
|
+
const aiAgentId: ObjectID = ObjectID.generate();
|
|
64
|
+
|
|
65
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
66
|
+
const transition: jest.SpyInstance = jest
|
|
67
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
68
|
+
.mockResolvedValue(1);
|
|
69
|
+
|
|
70
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
71
|
+
aiAgentId,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(claimed).toBe(run);
|
|
75
|
+
expect(transition).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(transition).toHaveBeenCalledWith(
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
aiRunId: run.id,
|
|
79
|
+
fromStatus: AIRunStatus.Queued,
|
|
80
|
+
// Guards against stale snapshots re-claiming or re-numbering.
|
|
81
|
+
expectedAttemptCount: 0,
|
|
82
|
+
set: expect.objectContaining({
|
|
83
|
+
status: AIRunStatus.Running,
|
|
84
|
+
attemptCount: 1,
|
|
85
|
+
startedAt: expect.any(Date),
|
|
86
|
+
lastHeartbeatAt: expect.any(Date),
|
|
87
|
+
/*
|
|
88
|
+
* The transition path bypasses column transformers, so the agent
|
|
89
|
+
* id must be its pre-transformed string form.
|
|
90
|
+
*/
|
|
91
|
+
aiAgentId: aiAgentId.toString(),
|
|
92
|
+
}),
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("a lost claim retries with the next candidate instead of returning it", async () => {
|
|
98
|
+
const lostRun: AIRun = fakeQueuedRun();
|
|
99
|
+
const wonRun: AIRun = fakeQueuedRun();
|
|
100
|
+
|
|
101
|
+
jest
|
|
102
|
+
.spyOn(AIRunService, "findOneBy")
|
|
103
|
+
.mockResolvedValueOnce(lostRun)
|
|
104
|
+
.mockResolvedValueOnce(wonRun);
|
|
105
|
+
jest
|
|
106
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
107
|
+
.mockResolvedValueOnce(0) // another agent won lostRun
|
|
108
|
+
.mockResolvedValueOnce(1);
|
|
109
|
+
|
|
110
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
111
|
+
aiAgentId: ObjectID.generate(),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(claimed).toBe(wonRun);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("an exception-based run without a triggering exception is finalized as Error and skipped", async () => {
|
|
118
|
+
const brokenRun: AIRun = fakeQueuedRun({ exceptionId: null });
|
|
119
|
+
const goodRun: AIRun = fakeQueuedRun();
|
|
120
|
+
|
|
121
|
+
jest
|
|
122
|
+
.spyOn(AIRunService, "findOneBy")
|
|
123
|
+
.mockResolvedValueOnce(brokenRun)
|
|
124
|
+
.mockResolvedValueOnce(goodRun);
|
|
125
|
+
const transition: jest.SpyInstance = jest
|
|
126
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
127
|
+
.mockResolvedValue(1);
|
|
128
|
+
|
|
129
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
130
|
+
aiAgentId: ObjectID.generate(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
expect(claimed).toBe(goodRun);
|
|
134
|
+
// Claim broken -> Error broken -> claim good.
|
|
135
|
+
expect(transition).toHaveBeenCalledTimes(3);
|
|
136
|
+
expect(transition).toHaveBeenNthCalledWith(
|
|
137
|
+
2,
|
|
138
|
+
expect.objectContaining({
|
|
139
|
+
aiRunId: brokenRun.id,
|
|
140
|
+
fromStatus: AIRunStatus.Running,
|
|
141
|
+
set: expect.objectContaining({
|
|
142
|
+
status: AIRunStatus.Error,
|
|
143
|
+
}),
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
* The executability guard is recipe-dependent: ImproveInstrumentation
|
|
150
|
+
* runs are enqueued by the inconclusive-investigation trigger with an
|
|
151
|
+
* incident/alert subject and NO telemetry exception — the claim must
|
|
152
|
+
* hand them to the worker, not Error them for lacking an exception.
|
|
153
|
+
*/
|
|
154
|
+
test("an ImproveInstrumentation run without an exception but with an incident subject is claimed, not errored", async () => {
|
|
155
|
+
const run: AIRun = fakeQueuedRun({
|
|
156
|
+
exceptionId: null,
|
|
157
|
+
codeFixTaskType: CodeFixTaskType.ImproveInstrumentation,
|
|
158
|
+
incidentId: ObjectID.generate(),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
162
|
+
const transition: jest.SpyInstance = jest
|
|
163
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
164
|
+
.mockResolvedValue(1);
|
|
165
|
+
|
|
166
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
167
|
+
aiAgentId: ObjectID.generate(),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(claimed).toBe(run);
|
|
171
|
+
expect(claimed?.codeFixTaskType).toBe(
|
|
172
|
+
CodeFixTaskType.ImproveInstrumentation,
|
|
173
|
+
);
|
|
174
|
+
// Exactly the claim CAS — no Error transition.
|
|
175
|
+
expect(transition).toHaveBeenCalledTimes(1);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("an ImproveInstrumentation run with an alert subject is claimed too", async () => {
|
|
179
|
+
const run: AIRun = fakeQueuedRun({
|
|
180
|
+
exceptionId: null,
|
|
181
|
+
codeFixTaskType: CodeFixTaskType.ImproveInstrumentation,
|
|
182
|
+
alertId: ObjectID.generate(),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
186
|
+
jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
|
|
187
|
+
|
|
188
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
189
|
+
aiAgentId: ObjectID.generate(),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(claimed).toBe(run);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
* FixFromIncident is the second incident/alert-subject recipe: enqueued
|
|
197
|
+
* by the user from the investigation panel, no telemetry exception — the
|
|
198
|
+
* same recipe grouping as ImproveInstrumentation in the guard.
|
|
199
|
+
*/
|
|
200
|
+
test("a FixFromIncident run without an exception but with an incident subject is claimed, not errored", async () => {
|
|
201
|
+
const run: AIRun = fakeQueuedRun({
|
|
202
|
+
exceptionId: null,
|
|
203
|
+
codeFixTaskType: CodeFixTaskType.FixFromIncident,
|
|
204
|
+
incidentId: ObjectID.generate(),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
208
|
+
const transition: jest.SpyInstance = jest
|
|
209
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
210
|
+
.mockResolvedValue(1);
|
|
211
|
+
|
|
212
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
213
|
+
aiAgentId: ObjectID.generate(),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(claimed).toBe(run);
|
|
217
|
+
expect(claimed?.codeFixTaskType).toBe(CodeFixTaskType.FixFromIncident);
|
|
218
|
+
// Exactly the claim CAS — no Error transition.
|
|
219
|
+
expect(transition).toHaveBeenCalledTimes(1);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("a FixFromIncident run with an alert subject is claimed too", async () => {
|
|
223
|
+
const run: AIRun = fakeQueuedRun({
|
|
224
|
+
exceptionId: null,
|
|
225
|
+
codeFixTaskType: CodeFixTaskType.FixFromIncident,
|
|
226
|
+
alertId: ObjectID.generate(),
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
230
|
+
jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
|
|
231
|
+
|
|
232
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
233
|
+
aiAgentId: ObjectID.generate(),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(claimed).toBe(run);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("a FixFromIncident run with NO subject at all is finalized as Error and skipped", async () => {
|
|
240
|
+
const brokenRun: AIRun = fakeQueuedRun({
|
|
241
|
+
exceptionId: null,
|
|
242
|
+
codeFixTaskType: CodeFixTaskType.FixFromIncident,
|
|
243
|
+
});
|
|
244
|
+
const goodRun: AIRun = fakeQueuedRun();
|
|
245
|
+
|
|
246
|
+
jest
|
|
247
|
+
.spyOn(AIRunService, "findOneBy")
|
|
248
|
+
.mockResolvedValueOnce(brokenRun)
|
|
249
|
+
.mockResolvedValueOnce(goodRun);
|
|
250
|
+
const transition: jest.SpyInstance = jest
|
|
251
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
252
|
+
.mockResolvedValue(1);
|
|
253
|
+
|
|
254
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
255
|
+
aiAgentId: ObjectID.generate(),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(claimed).toBe(goodRun);
|
|
259
|
+
expect(transition).toHaveBeenNthCalledWith(
|
|
260
|
+
2,
|
|
261
|
+
expect.objectContaining({
|
|
262
|
+
aiRunId: brokenRun.id,
|
|
263
|
+
fromStatus: AIRunStatus.Running,
|
|
264
|
+
set: expect.objectContaining({
|
|
265
|
+
status: AIRunStatus.Error,
|
|
266
|
+
errorMessage: expect.stringContaining("incident or alert subject"),
|
|
267
|
+
}),
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
/*
|
|
273
|
+
* FixPerformance is the third context kind: no exception AND no
|
|
274
|
+
* incident/alert subject — its trace evidence lives in taskContext. The
|
|
275
|
+
* guard must accept it when taskContext carries a traceId and Error it
|
|
276
|
+
* when the evidence is missing.
|
|
277
|
+
*/
|
|
278
|
+
test("a FixPerformance run with trace evidence in taskContext is claimed — no exception, no subject", async () => {
|
|
279
|
+
const run: AIRun = fakeQueuedRun({
|
|
280
|
+
exceptionId: null,
|
|
281
|
+
codeFixTaskType: CodeFixTaskType.FixPerformance,
|
|
282
|
+
taskContext: {
|
|
283
|
+
traceId: "abc123trace",
|
|
284
|
+
performanceFindings: [],
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
289
|
+
const transition: jest.SpyInstance = jest
|
|
290
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
291
|
+
.mockResolvedValue(1);
|
|
292
|
+
|
|
293
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
294
|
+
aiAgentId: ObjectID.generate(),
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(claimed).toBe(run);
|
|
298
|
+
expect(claimed?.codeFixTaskType).toBe(CodeFixTaskType.FixPerformance);
|
|
299
|
+
// Exactly the claim CAS — no Error transition.
|
|
300
|
+
expect(transition).toHaveBeenCalledTimes(1);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("a FixPerformance run with NO trace evidence is finalized as Error and skipped", async () => {
|
|
304
|
+
const brokenRun: AIRun = fakeQueuedRun({
|
|
305
|
+
exceptionId: null,
|
|
306
|
+
codeFixTaskType: CodeFixTaskType.FixPerformance,
|
|
307
|
+
});
|
|
308
|
+
const goodRun: AIRun = fakeQueuedRun();
|
|
309
|
+
|
|
310
|
+
jest
|
|
311
|
+
.spyOn(AIRunService, "findOneBy")
|
|
312
|
+
.mockResolvedValueOnce(brokenRun)
|
|
313
|
+
.mockResolvedValueOnce(goodRun);
|
|
314
|
+
const transition: jest.SpyInstance = jest
|
|
315
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
316
|
+
.mockResolvedValue(1);
|
|
317
|
+
|
|
318
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
319
|
+
aiAgentId: ObjectID.generate(),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
expect(claimed).toBe(goodRun);
|
|
323
|
+
expect(transition).toHaveBeenNthCalledWith(
|
|
324
|
+
2,
|
|
325
|
+
expect.objectContaining({
|
|
326
|
+
aiRunId: brokenRun.id,
|
|
327
|
+
fromStatus: AIRunStatus.Running,
|
|
328
|
+
set: expect.objectContaining({
|
|
329
|
+
status: AIRunStatus.Error,
|
|
330
|
+
errorMessage: expect.stringContaining("trace evidence"),
|
|
331
|
+
}),
|
|
332
|
+
}),
|
|
333
|
+
);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
test("a FixPerformance run carrying an incident id but no taskContext is still errored — the guard groups by context kind, not by whatever record happens to exist", async () => {
|
|
337
|
+
const brokenRun: AIRun = fakeQueuedRun({
|
|
338
|
+
exceptionId: null,
|
|
339
|
+
codeFixTaskType: CodeFixTaskType.FixPerformance,
|
|
340
|
+
incidentId: ObjectID.generate(),
|
|
341
|
+
});
|
|
342
|
+
const goodRun: AIRun = fakeQueuedRun();
|
|
343
|
+
|
|
344
|
+
jest
|
|
345
|
+
.spyOn(AIRunService, "findOneBy")
|
|
346
|
+
.mockResolvedValueOnce(brokenRun)
|
|
347
|
+
.mockResolvedValueOnce(goodRun);
|
|
348
|
+
const transition: jest.SpyInstance = jest
|
|
349
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
350
|
+
.mockResolvedValue(1);
|
|
351
|
+
|
|
352
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
353
|
+
aiAgentId: ObjectID.generate(),
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
expect(claimed).toBe(goodRun);
|
|
357
|
+
expect(transition).toHaveBeenNthCalledWith(
|
|
358
|
+
2,
|
|
359
|
+
expect.objectContaining({
|
|
360
|
+
aiRunId: brokenRun.id,
|
|
361
|
+
set: expect.objectContaining({
|
|
362
|
+
status: AIRunStatus.Error,
|
|
363
|
+
errorMessage: expect.stringContaining("trace evidence"),
|
|
364
|
+
}),
|
|
365
|
+
}),
|
|
366
|
+
);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test("an ImproveInstrumentation run with NO subject at all is finalized as Error and skipped", async () => {
|
|
370
|
+
const brokenRun: AIRun = fakeQueuedRun({
|
|
371
|
+
exceptionId: null,
|
|
372
|
+
codeFixTaskType: CodeFixTaskType.ImproveInstrumentation,
|
|
373
|
+
});
|
|
374
|
+
const goodRun: AIRun = fakeQueuedRun();
|
|
375
|
+
|
|
376
|
+
jest
|
|
377
|
+
.spyOn(AIRunService, "findOneBy")
|
|
378
|
+
.mockResolvedValueOnce(brokenRun)
|
|
379
|
+
.mockResolvedValueOnce(goodRun);
|
|
380
|
+
const transition: jest.SpyInstance = jest
|
|
381
|
+
.spyOn(AIRunService, "attemptStatusTransition")
|
|
382
|
+
.mockResolvedValue(1);
|
|
383
|
+
|
|
384
|
+
const claimed: AIRun | null = await AIRunService.claimNextQueuedCodeFixRun({
|
|
385
|
+
aiAgentId: ObjectID.generate(),
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
expect(claimed).toBe(goodRun);
|
|
389
|
+
expect(transition).toHaveBeenNthCalledWith(
|
|
390
|
+
2,
|
|
391
|
+
expect.objectContaining({
|
|
392
|
+
aiRunId: brokenRun.id,
|
|
393
|
+
fromStatus: AIRunStatus.Running,
|
|
394
|
+
set: expect.objectContaining({
|
|
395
|
+
status: AIRunStatus.Error,
|
|
396
|
+
errorMessage: expect.stringContaining("incident or alert subject"),
|
|
397
|
+
}),
|
|
398
|
+
}),
|
|
399
|
+
);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import AIRunService from "../../../Server/Services/AIRunService";
|
|
2
|
+
import AIRun from "../../../Models/DatabaseModels/AIRun";
|
|
3
|
+
import AIRunType from "../../../Types/AI/AIRunType";
|
|
4
|
+
import AIRunStatus from "../../../Types/AI/AIRunStatus";
|
|
5
|
+
import AIRunHumanVerdict from "../../../Types/AI/AIRunHumanVerdict";
|
|
6
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
7
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
8
|
+
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
9
|
+
import { describe, expect, test, afterEach } from "@jest/globals";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Human verdict capture (Phase 2 measurement layer): the one-click
|
|
13
|
+
* Confirm / Reject on the investigation panel lands here, via
|
|
14
|
+
* POST /ai-investigation/verdict → applyHumanVerdictToLatestInvestigation.
|
|
15
|
+
* Contract under test: the verdict applies to the LATEST COMPLETED
|
|
16
|
+
* investigation for the subject, rejects when none exists, stores
|
|
17
|
+
* verdict + at + byUserId, and overwriting is allowed (a user may change
|
|
18
|
+
* their mind — there is deliberately no "already has a verdict" guard).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const incidentId: ObjectID = ObjectID.generate();
|
|
22
|
+
const alertId: ObjectID = ObjectID.generate();
|
|
23
|
+
const userId: ObjectID = ObjectID.generate();
|
|
24
|
+
|
|
25
|
+
function fakeRun(): AIRun {
|
|
26
|
+
return { id: ObjectID.generate() } as unknown as AIRun;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("AIRunService.applyHumanVerdictToLatestInvestigation", () => {
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
jest.restoreAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("a subjectless call is rejected before any query", async () => {
|
|
35
|
+
const findOneBy: jest.SpyInstance = jest.spyOn(AIRunService, "findOneBy");
|
|
36
|
+
|
|
37
|
+
await expect(
|
|
38
|
+
AIRunService.applyHumanVerdictToLatestInvestigation({
|
|
39
|
+
verdict: AIRunHumanVerdict.Confirmed,
|
|
40
|
+
verdictByUserId: userId,
|
|
41
|
+
}),
|
|
42
|
+
).rejects.toThrow(BadDataException);
|
|
43
|
+
|
|
44
|
+
expect(findOneBy).not.toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("no completed investigation → reject with a clear message, nothing written", async () => {
|
|
48
|
+
const findOneBy: jest.SpyInstance = jest
|
|
49
|
+
.spyOn(AIRunService, "findOneBy")
|
|
50
|
+
.mockResolvedValue(null);
|
|
51
|
+
const updateOneById: jest.SpyInstance = jest.spyOn(
|
|
52
|
+
AIRunService,
|
|
53
|
+
"updateOneById",
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
await expect(
|
|
57
|
+
AIRunService.applyHumanVerdictToLatestInvestigation({
|
|
58
|
+
incidentId,
|
|
59
|
+
verdict: AIRunHumanVerdict.Confirmed,
|
|
60
|
+
verdictByUserId: userId,
|
|
61
|
+
}),
|
|
62
|
+
).rejects.toThrow(/No completed AI investigation/);
|
|
63
|
+
|
|
64
|
+
// The lookup must target the LATEST COMPLETED investigation.
|
|
65
|
+
expect(findOneBy).toHaveBeenCalledWith(
|
|
66
|
+
expect.objectContaining({
|
|
67
|
+
query: expect.objectContaining({
|
|
68
|
+
runType: AIRunType.Investigation,
|
|
69
|
+
status: AIRunStatus.Completed,
|
|
70
|
+
triggeredByIncidentId: incidentId,
|
|
71
|
+
}),
|
|
72
|
+
sort: expect.objectContaining({ createdAt: SortOrder.Descending }),
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
expect(updateOneById).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("happy path (incident): stores verdict + at + byUserId on the run and returns {runId, verdict}", async () => {
|
|
79
|
+
const run: AIRun = fakeRun();
|
|
80
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
81
|
+
const updateOneById: jest.SpyInstance = jest
|
|
82
|
+
.spyOn(AIRunService, "updateOneById")
|
|
83
|
+
.mockResolvedValue(undefined as never);
|
|
84
|
+
|
|
85
|
+
const result: { runId: ObjectID; verdict: AIRunHumanVerdict } =
|
|
86
|
+
await AIRunService.applyHumanVerdictToLatestInvestigation({
|
|
87
|
+
incidentId,
|
|
88
|
+
verdict: AIRunHumanVerdict.Confirmed,
|
|
89
|
+
verdictByUserId: userId,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(result.runId).toBe(run.id);
|
|
93
|
+
expect(result.verdict).toBe(AIRunHumanVerdict.Confirmed);
|
|
94
|
+
|
|
95
|
+
expect(updateOneById).toHaveBeenCalledWith(
|
|
96
|
+
expect.objectContaining({
|
|
97
|
+
id: run.id,
|
|
98
|
+
data: expect.objectContaining({
|
|
99
|
+
humanVerdict: AIRunHumanVerdict.Confirmed,
|
|
100
|
+
humanVerdictAt: expect.any(Date),
|
|
101
|
+
humanVerdictByUserId: userId,
|
|
102
|
+
}),
|
|
103
|
+
props: expect.objectContaining({ isRoot: true }),
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("happy path (alert): the lookup keys on triggeredByAlertId", async () => {
|
|
109
|
+
const run: AIRun = fakeRun();
|
|
110
|
+
const findOneBy: jest.SpyInstance = jest
|
|
111
|
+
.spyOn(AIRunService, "findOneBy")
|
|
112
|
+
.mockResolvedValue(run);
|
|
113
|
+
jest
|
|
114
|
+
.spyOn(AIRunService, "updateOneById")
|
|
115
|
+
.mockResolvedValue(undefined as never);
|
|
116
|
+
|
|
117
|
+
await AIRunService.applyHumanVerdictToLatestInvestigation({
|
|
118
|
+
alertId,
|
|
119
|
+
verdict: AIRunHumanVerdict.Rejected,
|
|
120
|
+
verdictByUserId: userId,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(findOneBy).toHaveBeenCalledWith(
|
|
124
|
+
expect.objectContaining({
|
|
125
|
+
query: expect.objectContaining({
|
|
126
|
+
runType: AIRunType.Investigation,
|
|
127
|
+
status: AIRunStatus.Completed,
|
|
128
|
+
triggeredByAlertId: alertId,
|
|
129
|
+
}),
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("idempotent overwrite: a run that already carries a verdict is simply re-written", async () => {
|
|
135
|
+
// The service deliberately does NOT guard on an existing verdict.
|
|
136
|
+
const run: AIRun = {
|
|
137
|
+
id: ObjectID.generate(),
|
|
138
|
+
humanVerdict: AIRunHumanVerdict.Confirmed,
|
|
139
|
+
} as unknown as AIRun;
|
|
140
|
+
jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
|
|
141
|
+
const updateOneById: jest.SpyInstance = jest
|
|
142
|
+
.spyOn(AIRunService, "updateOneById")
|
|
143
|
+
.mockResolvedValue(undefined as never);
|
|
144
|
+
|
|
145
|
+
const result: { runId: ObjectID; verdict: AIRunHumanVerdict } =
|
|
146
|
+
await AIRunService.applyHumanVerdictToLatestInvestigation({
|
|
147
|
+
incidentId,
|
|
148
|
+
verdict: AIRunHumanVerdict.Rejected,
|
|
149
|
+
verdictByUserId: userId,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(result.verdict).toBe(AIRunHumanVerdict.Rejected);
|
|
153
|
+
expect(updateOneById).toHaveBeenCalledWith(
|
|
154
|
+
expect.objectContaining({
|
|
155
|
+
data: expect.objectContaining({
|
|
156
|
+
humanVerdict: AIRunHumanVerdict.Rejected,
|
|
157
|
+
}),
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import AIService, {
|
|
2
2
|
AUTONOMOUS_AI_FEATURES,
|
|
3
3
|
AutonomousBudgetStatus,
|
|
4
|
+
LEGACY_AUTONOMOUS_AI_FEATURES,
|
|
5
|
+
AI_ALERT_INVESTIGATION_FEATURE,
|
|
6
|
+
AI_CODE_FIX_FEATURE,
|
|
7
|
+
AI_CONFIDENCE_CLASSIFICATION_FEATURE,
|
|
8
|
+
AI_INCIDENT_INVESTIGATION_FEATURE,
|
|
9
|
+
AI_INSIGHT_TRIAGE_FEATURE,
|
|
10
|
+
AI_INVESTIGATION_GRADING_FEATURE,
|
|
11
|
+
RUNBOOK_AI_STEP_FEATURE,
|
|
12
|
+
WORKFLOW_AI_FEATURE,
|
|
4
13
|
} from "../../../Server/Services/AIService";
|
|
5
|
-
import
|
|
14
|
+
import AIInvestigationQueue from "../../../Server/Utils/AI/SRE/InvestigationQueue";
|
|
6
15
|
import LlmLogService from "../../../Server/Services/LlmLogService";
|
|
7
16
|
import ProjectService from "../../../Server/Services/ProjectService";
|
|
8
17
|
import AIRunService from "../../../Server/Services/AIRunService";
|
|
@@ -32,6 +41,87 @@ function fakeProject(limit: number | undefined): Project {
|
|
|
32
41
|
} as unknown as Project;
|
|
33
42
|
}
|
|
34
43
|
|
|
44
|
+
/*
|
|
45
|
+
* The budget is enforced by matching PERSISTED LlmLog.feature strings against
|
|
46
|
+
* AUTONOMOUS_AI_FEATURES, so these labels are data, not display text. Changing
|
|
47
|
+
* one silently rewrites a project's usage history for the current UTC day:
|
|
48
|
+
* older rows stop matching, usedTokensToday collapses toward zero, and an
|
|
49
|
+
* already-exhausted project gets a fresh full budget. These tests pin the
|
|
50
|
+
* exact wire values and the legacy aliases so no rename can do that quietly.
|
|
51
|
+
*/
|
|
52
|
+
describe("AUTONOMOUS_AI_FEATURES persisted labels", () => {
|
|
53
|
+
test("each label has its exact persisted value", () => {
|
|
54
|
+
expect(AI_INCIDENT_INVESTIGATION_FEATURE).toBe("AI Incident Investigation");
|
|
55
|
+
expect(AI_ALERT_INVESTIGATION_FEATURE).toBe("AI Alert Investigation");
|
|
56
|
+
expect(AI_INVESTIGATION_GRADING_FEATURE).toBe("AI Investigation Grading");
|
|
57
|
+
expect(AI_CONFIDENCE_CLASSIFICATION_FEATURE).toBe(
|
|
58
|
+
"AI Confidence Classification",
|
|
59
|
+
);
|
|
60
|
+
expect(AI_CODE_FIX_FEATURE).toBe("AI Code Fix");
|
|
61
|
+
expect(AI_INSIGHT_TRIAGE_FEATURE).toBe("AI Insight Triage");
|
|
62
|
+
expect(RUNBOOK_AI_STEP_FEATURE).toBe("Runbook AI Step");
|
|
63
|
+
expect(WORKFLOW_AI_FEATURE).toBe("Workflow AI");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("the budget match-list covers every autonomous feature", () => {
|
|
67
|
+
for (const feature of [
|
|
68
|
+
AI_INCIDENT_INVESTIGATION_FEATURE,
|
|
69
|
+
AI_ALERT_INVESTIGATION_FEATURE,
|
|
70
|
+
AI_INVESTIGATION_GRADING_FEATURE,
|
|
71
|
+
AI_CONFIDENCE_CLASSIFICATION_FEATURE,
|
|
72
|
+
AI_CODE_FIX_FEATURE,
|
|
73
|
+
AI_INSIGHT_TRIAGE_FEATURE,
|
|
74
|
+
RUNBOOK_AI_STEP_FEATURE,
|
|
75
|
+
WORKFLOW_AI_FEATURE,
|
|
76
|
+
]) {
|
|
77
|
+
expect(AUTONOMOUS_AI_FEATURES).toContain(feature);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* The budget hole this guards: the six labels below were persisted by the
|
|
83
|
+
* pre-rename code. Dropping them from the match-list stops LlmLog rows that
|
|
84
|
+
* ALREADY carry them from counting — during the deploy window (old and new
|
|
85
|
+
* pods write different labels into the same UTC day) and for any row the
|
|
86
|
+
* backfill migration missed. A future cleanup must fail here and go read the
|
|
87
|
+
* retention argument in AIService before deleting them.
|
|
88
|
+
*/
|
|
89
|
+
test("the six legacy Sentinel labels are still counted by the budget", () => {
|
|
90
|
+
expect(LEGACY_AUTONOMOUS_AI_FEATURES).toEqual([
|
|
91
|
+
"Sentinel Incident Investigation",
|
|
92
|
+
"Sentinel Alert Investigation",
|
|
93
|
+
"Sentinel Investigation Grading",
|
|
94
|
+
"Sentinel Confidence Classification",
|
|
95
|
+
"Sentinel Code Fix",
|
|
96
|
+
"Sentinel Insight Triage",
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
for (const legacyFeature of LEGACY_AUTONOMOUS_AI_FEATURES) {
|
|
100
|
+
expect(AUTONOMOUS_AI_FEATURES).toContain(legacyFeature);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* Nothing but the constants and the legacy aliases may reach the list — a
|
|
106
|
+
* raw literal here is how a writer and the budget silently drift apart.
|
|
107
|
+
*/
|
|
108
|
+
test("the match-list is exactly the current labels plus the legacy aliases", () => {
|
|
109
|
+
expect([...AUTONOMOUS_AI_FEATURES].sort()).toEqual(
|
|
110
|
+
[
|
|
111
|
+
AI_INCIDENT_INVESTIGATION_FEATURE,
|
|
112
|
+
AI_ALERT_INVESTIGATION_FEATURE,
|
|
113
|
+
AI_INVESTIGATION_GRADING_FEATURE,
|
|
114
|
+
AI_CONFIDENCE_CLASSIFICATION_FEATURE,
|
|
115
|
+
AI_CODE_FIX_FEATURE,
|
|
116
|
+
AI_INSIGHT_TRIAGE_FEATURE,
|
|
117
|
+
RUNBOOK_AI_STEP_FEATURE,
|
|
118
|
+
WORKFLOW_AI_FEATURE,
|
|
119
|
+
...LEGACY_AUTONOMOUS_AI_FEATURES,
|
|
120
|
+
].sort(),
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
35
125
|
describe("AIService.getAutonomousDailyBudgetStatus", () => {
|
|
36
126
|
const projectId: ObjectID = ObjectID.generate();
|
|
37
127
|
|
|
@@ -107,7 +197,7 @@ describe("AIService.getAutonomousDailyBudgetStatus", () => {
|
|
|
107
197
|
});
|
|
108
198
|
});
|
|
109
199
|
|
|
110
|
-
describe("
|
|
200
|
+
describe("AIInvestigationQueue budget skip", () => {
|
|
111
201
|
afterEach(() => {
|
|
112
202
|
jest.restoreAllMocks();
|
|
113
203
|
});
|
|
@@ -120,7 +210,7 @@ describe("SentinelInvestigationQueue budget skip", () => {
|
|
|
120
210
|
});
|
|
121
211
|
const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
|
|
122
212
|
|
|
123
|
-
await
|
|
213
|
+
await AIInvestigationQueue.enqueue({
|
|
124
214
|
projectId: ObjectID.generate(),
|
|
125
215
|
subjectAlertId: ObjectID.generate(),
|
|
126
216
|
});
|
|
@@ -134,7 +224,7 @@ describe("SentinelInvestigationQueue budget skip", () => {
|
|
|
134
224
|
.mockRejectedValue(new Error("db down"));
|
|
135
225
|
const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
|
|
136
226
|
|
|
137
|
-
await
|
|
227
|
+
await AIInvestigationQueue.enqueue({
|
|
138
228
|
projectId: ObjectID.generate(),
|
|
139
229
|
subjectAlertId: ObjectID.generate(),
|
|
140
230
|
});
|
|
@@ -161,7 +251,7 @@ describe("SentinelInvestigationQueue budget skip", () => {
|
|
|
161
251
|
"attemptStatusTransition",
|
|
162
252
|
);
|
|
163
253
|
|
|
164
|
-
await
|
|
254
|
+
await AIInvestigationQueue.processRun({
|
|
165
255
|
id: ObjectID.generate(),
|
|
166
256
|
projectId: ObjectID.generate(),
|
|
167
257
|
attemptCount: 0,
|