@oneuptime/common 11.5.7 → 11.5.9
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 +15 -6
- package/Models/DatabaseModels/AIRun.ts +68 -0
- package/Models/DatabaseModels/AIRunEvent.ts +34 -1
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +215 -0
- package/Models/DatabaseModels/Project.ts +25 -0
- package/Models/DatabaseModels/StatusPage.ts +42 -0
- package/Server/API/AIAgentTaskAPI.ts +38 -12
- package/Server/API/AIAgentTaskLogAPI.ts +49 -0
- package/Server/API/AIChatAPI.ts +16 -0
- package/Server/API/AIReadinessAPI.ts +84 -0
- package/Server/API/CodeFixRunAPI.ts +190 -57
- package/Server/API/TelemetryExceptionAPI.ts +6 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.ts +41 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.ts +95 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +1 -1
- package/Server/Middleware/ProjectAuthorization.ts +1 -1
- package/Server/Services/AIRunEventService.ts +15 -1
- package/Server/Services/AIRunService.ts +48 -12
- package/Server/Services/LlmProviderService.ts +2 -0
- package/Server/Services/ProjectService.ts +42 -0
- package/Server/Services/StatusPageService.ts +87 -0
- package/Server/Services/TelemetryExceptionService.ts +19 -90
- package/Server/Types/Markdown.ts +9 -9
- package/Server/Types/MarkdownSlugify.ts +47 -0
- package/Server/Utils/AI/AIRunPrivacyFilter.ts +106 -0
- package/Server/Utils/AI/AIRunTranscript.ts +240 -0
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +9 -0
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +119 -5
- package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +75 -0
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +235 -0
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +2 -3
- package/Server/Utils/AI/Toolbox/CodeTools.ts +883 -0
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +519 -0
- package/Server/Utils/AI/Toolbox/Index.ts +27 -0
- package/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.ts +279 -0
- package/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.ts +19 -1
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +600 -0
- package/Server/Utils/CodeRepository/StackTraceRepoResolver.ts +7 -2
- package/Server/Utils/LLM/LLMService.ts +397 -18
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +4 -11
- package/Tests/Models/StatusPageEnableMcpServer.test.ts +125 -0
- package/Tests/Server/Services/StatusPageServiceMcp.test.ts +223 -0
- package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +26 -3
- package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +12 -0
- package/Tests/Server/Types/Markdown.test.ts +106 -0
- package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +295 -0
- package/Tests/Server/Utils/AI/AIRunTranscript.test.ts +182 -0
- package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +411 -0
- package/Tests/Server/Utils/AI/CodeTools.test.ts +596 -0
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +475 -0
- package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +548 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +142 -0
- package/Tests/Server/Utils/AI/ScheduledMaintenanceTools.test.ts +176 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.test.ts +63 -0
- package/Tests/Server/Utils/GitHubGetFileContent.test.ts +197 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +502 -0
- package/Tests/Types/AI/AIAgentTaskStatus.test.ts +7 -6
- package/Tests/Types/AI/AIChatPageContext.test.ts +0 -0
- package/Tests/Types/AI/AIRunStatus.test.ts +42 -0
- package/Tests/Types/Log/LogSeverity.test.ts +78 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +167 -0
- package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +66 -0
- package/Tests/UI/Utils/AIChatExport/ChatWidgetData.test.ts +319 -0
- package/Tests/UI/Utils/AIChatExport/ChatWidgetMarkdown.test.ts +188 -0
- package/Types/AI/AIAgentTaskStatus.ts +13 -0
- package/Types/AI/AIChatPageContext.ts +137 -0
- package/Types/AI/AIChatTypes.ts +44 -0
- package/Types/AI/AIFixReadiness.ts +46 -0
- package/Types/AI/AIRunStatus.ts +11 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/Log/LogSeverity.ts +61 -0
- package/Types/Monitor/SnmpMonitor/SnmpVersion.ts +40 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -2
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +3 -1
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +8 -2
- package/UI/Components/EditionLabel/EditionLabel.tsx +821 -331
- package/UI/Components/Forms/BasicForm.tsx +26 -8
- package/UI/Styles/Theme.css +1314 -0
- package/UI/Utils/AIChatExport/ChatWidgetData.ts +316 -0
- package/UI/Utils/AIChatExport/ChatWidgetMarkdown.ts +349 -0
- package/UI/Utils/AIChatExport/ConversationMarkdown.ts +177 -0
- package/UI/Utils/AIChatExport/MarkdownBlocks.ts +327 -0
- package/UI/Utils/AIChatExport/MarkdownSafety.ts +215 -0
- package/UI/Utils/DownloadFile.ts +54 -0
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +15 -7
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIRun.js +69 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIRunEvent.js +31 -0
- package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +225 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +27 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +43 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskAPI.js +37 -11
- package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskLogAPI.js +32 -7
- package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +9 -0
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIReadinessAPI.js +57 -0
- package/build/dist/Server/API/AIReadinessAPI.js.map +1 -0
- package/build/dist/Server/API/CodeFixRunAPI.js +165 -51
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +4 -0
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js +80 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js +37 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +1 -1
- package/build/dist/Server/Services/AIRunEventService.js +8 -0
- package/build/dist/Server/Services/AIRunEventService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +39 -3
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/LlmProviderService.js +2 -0
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +39 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +81 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +14 -61
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +8 -8
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/MarkdownSlugify.js +47 -0
- package/build/dist/Server/Types/MarkdownSlugify.js.map +1 -0
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +82 -0
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -0
- package/build/dist/Server/Utils/AI/AIRunTranscript.js +180 -0
- package/build/dist/Server/Utils/AI/AIRunTranscript.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +103 -5
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +55 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +211 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +654 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +389 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +19 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js +239 -0
- package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js +19 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +439 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js +1 -1
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +275 -19
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +2 -11
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Types/AI/AIAgentTaskStatus.js +12 -0
- package/build/dist/Types/AI/AIAgentTaskStatus.js.map +1 -1
- package/build/dist/Types/AI/AIChatPageContext.js +101 -0
- package/build/dist/Types/AI/AIChatPageContext.js.map +1 -0
- package/build/dist/Types/AI/AIChatTypes.js +2 -0
- package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
- package/build/dist/Types/AI/AIFixReadiness.js +9 -0
- package/build/dist/Types/AI/AIFixReadiness.js.map +1 -0
- package/build/dist/Types/AI/AIRunStatus.js +11 -0
- package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Log/LogSeverity.js +56 -0
- package/build/dist/Types/Log/LogSeverity.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js +38 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +9 -2
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +3 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +9 -2
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +424 -139
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +24 -6
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js +217 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js +234 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +111 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js +233 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js +134 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js.map +1 -0
- package/build/dist/UI/Utils/DownloadFile.js +41 -0
- package/build/dist/UI/Utils/DownloadFile.js.map +1 -0
- package/package.json +5 -1
|
@@ -13,20 +13,18 @@ import CodeFixTaskType, {
|
|
|
13
13
|
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
14
14
|
import AIRunService from "./AIRunService";
|
|
15
15
|
import FixRunBudget from "../Utils/AI/CodeFix/FixRunBudget";
|
|
16
|
-
import
|
|
17
|
-
import LlmProviderService from "./LlmProviderService";
|
|
18
|
-
import ProjectService from "./ProjectService";
|
|
16
|
+
import CodeFixReadiness from "../Utils/AI/CodeFix/CodeFixReadiness";
|
|
19
17
|
import ServiceService from "./ServiceService";
|
|
20
18
|
import CodeRepositoryService from "./CodeRepositoryService";
|
|
21
19
|
import { RepoResolution } from "../Utils/CodeRepository/StackTraceRepoResolver";
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
import {
|
|
21
|
+
AIFixReadiness,
|
|
22
|
+
AIFixReadinessCheck,
|
|
23
|
+
} from "../../Types/AI/AIFixReadiness";
|
|
25
24
|
import TelemetryService from "../../Models/DatabaseModels/Service";
|
|
26
25
|
import QueryHelper from "../Types/Database/QueryHelper";
|
|
27
26
|
import ModelPermission from "../Types/Database/Permissions/Index";
|
|
28
27
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
29
|
-
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
30
28
|
import Query from "../Types/Database/Query";
|
|
31
29
|
import Includes from "../../Types/BaseDatabase/Includes";
|
|
32
30
|
import logger from "../Utils/Logger";
|
|
@@ -46,24 +44,6 @@ export interface CreateCodeFixRunForExceptionParams {
|
|
|
46
44
|
taskType?: CodeFixTaskType | undefined;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
export type AIFixReadinessCheckId =
|
|
50
|
-
| "llmProvider"
|
|
51
|
-
| "repositoryResolved"
|
|
52
|
-
| "agentAvailable";
|
|
53
|
-
|
|
54
|
-
export interface AIFixReadinessCheck {
|
|
55
|
-
id: AIFixReadinessCheckId;
|
|
56
|
-
ok: boolean;
|
|
57
|
-
title: string;
|
|
58
|
-
// Shown to the user when ok is false — says exactly what to do next.
|
|
59
|
-
detail: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface AIFixReadiness {
|
|
63
|
-
ready: boolean;
|
|
64
|
-
checks: Array<AIFixReadinessCheck>;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
47
|
export interface DashboardServiceSummary {
|
|
68
48
|
/*
|
|
69
49
|
* Polymorphic: a real Service, a Host/DockerHost/KubernetesCluster id, or
|
|
@@ -124,55 +104,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
124
104
|
const projectId: ObjectID = telemetryException.projectId;
|
|
125
105
|
|
|
126
106
|
/*
|
|
127
|
-
* 1. An LLM provider the agent may use
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* simply wins when one exists.
|
|
131
|
-
*/
|
|
132
|
-
const llmProvider: LlmProvider | null =
|
|
133
|
-
await LlmProviderService.getLlmProviderForMeteredAgentPath(projectId);
|
|
134
|
-
|
|
135
|
-
let llmOk: boolean = Boolean(llmProvider);
|
|
136
|
-
let llmDetail: string = llmOk
|
|
137
|
-
? ""
|
|
138
|
-
: "AI fix tasks need an LLM provider. Add one in Project Settings > AI > LLM Providers. Self-hosted instances can alternatively set the GLOBAL_LLM_PROVIDER_* environment variables to register a global provider for every project.";
|
|
139
|
-
|
|
140
|
-
/*
|
|
141
|
-
* A resolved provider must also be PAYABLE, or the run passes readiness
|
|
142
|
-
* here and dies at its first completion call instead. Mirrors the
|
|
143
|
-
* billing gate in AIService.executeWithLogging: only a COSTED global
|
|
144
|
-
* provider on cloud bills the project's AI balance per call —
|
|
145
|
-
* project-owned and free-global providers consume no balance and must
|
|
146
|
-
* not require one.
|
|
107
|
+
* 1. An LLM provider the agent may use — the same gate the project-wide
|
|
108
|
+
* AI Tasks page renders, so the two surfaces can never disagree about
|
|
109
|
+
* whether this project has a usable provider.
|
|
147
110
|
*/
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
billingEnabled &&
|
|
153
|
-
(llmProvider.isGlobalLlm || false) &&
|
|
154
|
-
(llmProvider.costPerMillionTokensInUSDCents || 0) > 0
|
|
155
|
-
) {
|
|
156
|
-
const project: Project | null = await ProjectService.findOneById({
|
|
157
|
-
id: projectId,
|
|
158
|
-
select: { aiCurrentBalanceInUSDCents: true },
|
|
159
|
-
props: { isRoot: true },
|
|
111
|
+
const llmCheck: AIFixReadinessCheck =
|
|
112
|
+
await CodeFixReadiness.getLlmProviderCheck({
|
|
113
|
+
projectId,
|
|
114
|
+
billingEnabled: params.billingEnabled,
|
|
160
115
|
});
|
|
161
116
|
|
|
162
|
-
if (!project || (project.aiCurrentBalanceInUSDCents || 0) <= 0) {
|
|
163
|
-
llmOk = false;
|
|
164
|
-
llmDetail =
|
|
165
|
-
"AI fix tasks would use the OneUptime-hosted LLM provider, which is billed against your AI balance — and the project's balance is empty. Recharge it in Project Settings > AI Credits, or add your own LLM provider in Project Settings > AI > LLM Providers.";
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const llmCheck: AIFixReadinessCheck = {
|
|
170
|
-
id: "llmProvider",
|
|
171
|
-
ok: llmOk,
|
|
172
|
-
title: "LLM provider",
|
|
173
|
-
detail: llmDetail,
|
|
174
|
-
};
|
|
175
|
-
|
|
176
117
|
/*
|
|
177
118
|
* 2. A repository must RESOLVE for this exception — computed at runtime
|
|
178
119
|
* from the stack trace (path matching over connected repos), falling
|
|
@@ -223,25 +164,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
223
164
|
};
|
|
224
165
|
}
|
|
225
166
|
|
|
226
|
-
//
|
|
227
|
-
const
|
|
228
|
-
await
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
? anyAgent
|
|
232
|
-
: null
|
|
233
|
-
: null;
|
|
234
|
-
|
|
235
|
-
const agentCheck: AIFixReadinessCheck = {
|
|
236
|
-
id: "agentAvailable",
|
|
237
|
-
ok: Boolean(connectedAgent),
|
|
238
|
-
title: "AI agent online",
|
|
239
|
-
detail: connectedAgent
|
|
240
|
-
? ""
|
|
241
|
-
: anyAgent
|
|
242
|
-
? `The AI agent "${anyAgent.name || "agent"}" has not reported in — check that its container is running.`
|
|
243
|
-
: "No AI agent is available for this project. Self-hosted: create an agent under Settings > AI > AI Agents and run its container. Cloud: the shared fleet appears here automatically once enabled.",
|
|
244
|
-
};
|
|
167
|
+
// 3. An agent must be alive to pick the task up.
|
|
168
|
+
const agentCheck: AIFixReadinessCheck =
|
|
169
|
+
await CodeFixReadiness.getAgentCheck({
|
|
170
|
+
projectId,
|
|
171
|
+
});
|
|
245
172
|
|
|
246
173
|
const checks: Array<AIFixReadinessCheck> = [
|
|
247
174
|
llmCheck,
|
|
@@ -387,8 +314,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
387
314
|
taskType === CodeFixTaskType.FixException
|
|
388
315
|
? QueryHelper.equalToOrNull(CodeFixTaskType.FixException)
|
|
389
316
|
: taskType,
|
|
317
|
+
// Every terminal status — see AIRunStatusHelper.isTerminalStatus.
|
|
390
318
|
status: QueryHelper.notIn([
|
|
391
319
|
AIRunStatus.Completed,
|
|
320
|
+
AIRunStatus.NoFixFound,
|
|
392
321
|
AIRunStatus.Error,
|
|
393
322
|
AIRunStatus.Cancelled,
|
|
394
323
|
AIRunStatus.Stale,
|
package/Server/Types/Markdown.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Renderer, marked } from "marked";
|
|
2
2
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
3
|
+
import markdownSlugify from "./MarkdownSlugify";
|
|
3
4
|
|
|
4
5
|
export type MarkdownRenderer = Renderer;
|
|
5
6
|
|
|
@@ -235,15 +236,14 @@ export default class Markdown {
|
|
|
235
236
|
return renderer;
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
.replace(/^-|-$/g, "");
|
|
239
|
+
/*
|
|
240
|
+
* Heading text -> the `id` used for in-page anchors. The rules live in
|
|
241
|
+
* MarkdownSlugify.ts, a dependency-free module, so the docs anchor scripts
|
|
242
|
+
* (Scripts/Docs/CheckAnchors.ts, FixAnchors.ts) can share them without
|
|
243
|
+
* pulling in marked or the telemetry stack — see the comment there.
|
|
244
|
+
*/
|
|
245
|
+
public static slugify(text: string): string {
|
|
246
|
+
return markdownSlugify(text);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
private static getDocsRenderer(): Renderer {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Heading text -> the `id` used for in-page anchors.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for anchor ids. The docs renderer
|
|
5
|
+
* (Common/Server/Types/Markdown.ts) exposes it as Markdown.slugify, and the
|
|
6
|
+
* docs anchor scripts (Scripts/Docs/CheckAnchors.ts, Scripts/Docs/FixAnchors.ts)
|
|
7
|
+
* import it directly; a second copy of these rules would drift and then pass a
|
|
8
|
+
* link the renderer serves as a 404.
|
|
9
|
+
*
|
|
10
|
+
* It lives in its own module with ZERO imports on purpose: Markdown.ts pulls in
|
|
11
|
+
* marked and the telemetry stack, which only resolve inside a fully installed
|
|
12
|
+
* package. The scripts run in CI with nothing but the root npm install, so they
|
|
13
|
+
* must be able to load the slugify rules without any of that.
|
|
14
|
+
*
|
|
15
|
+
* The character class keeps letters and numbers in ANY script, via \p{L} and
|
|
16
|
+
* \p{N} with the /u flag. It used to be `\w`, which is ASCII-only — so every
|
|
17
|
+
* Cyrillic, CJK and Devanagari heading was stripped to nothing and rendered
|
|
18
|
+
* as id="", breaking every anchor in those locales. Accented Latin lost the
|
|
19
|
+
* accented letter alone ("gravité" -> "gravit").
|
|
20
|
+
*
|
|
21
|
+
* \p{M} (combining marks) is required alongside \p{L}: Devanagari matras and
|
|
22
|
+
* Arabic/Thai vowel signs are marks, not letters, so without it Hindi headings
|
|
23
|
+
* come out mangled rather than merely transliterated ("लॉग" -> "लग"). It also
|
|
24
|
+
* covers decomposed (NFD) Latin, where "é" is "e" + a combining accent.
|
|
25
|
+
*
|
|
26
|
+
* Variation selectors are dropped first. They are marks too, so \p{M} would
|
|
27
|
+
* otherwise keep them — and an emoji heading like "⚠️ Important" carries an
|
|
28
|
+
* invisible U+FE0F that would survive its emoji and lead the id.
|
|
29
|
+
*
|
|
30
|
+
* `_` is listed explicitly because \p{L}/\p{N} do not cover it but the old
|
|
31
|
+
* `\w` did, and real headings depend on it — e.g. "`ceph_health_status` is 1
|
|
32
|
+
* but no incident fires". Dropping it would silently renumber existing
|
|
33
|
+
* English anchors and break inbound deep links.
|
|
34
|
+
*/
|
|
35
|
+
const slugify: (text: string) => string = (text: string): string => {
|
|
36
|
+
return text
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/<[^>]*>/g, "")
|
|
39
|
+
.replace(/&[^;]+;/g, "")
|
|
40
|
+
.replace(/[\uFE00-\uFE0F\u{E0100}-\u{E01EF}]/gu, "")
|
|
41
|
+
.replace(/[^\p{L}\p{N}\p{M}_\s-]/gu, "")
|
|
42
|
+
.replace(/\s+/g, "-")
|
|
43
|
+
.replace(/-+/g, "-")
|
|
44
|
+
.replace(/^-|-$/g, "");
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default slugify;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
2
|
+
import { FindWhereProperty } from "../../../Types/BaseDatabase/Query";
|
|
3
|
+
import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
|
|
4
|
+
import AIRunType from "../../../Types/AI/AIRunType";
|
|
5
|
+
import Text from "../../../Types/Text";
|
|
6
|
+
import { combineWithPrivacyClause } from "../PrivacyFilterUtil";
|
|
7
|
+
import { Raw } from "typeorm";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* AIRun mixes two kinds of row under one table:
|
|
11
|
+
*
|
|
12
|
+
* - Chat and investigation runs are PERSONAL. They hang off a conversation
|
|
13
|
+
* and carry the user's own prompt trail, so only their author may read
|
|
14
|
+
* them. This is what AIChatPrivacyFilter's flat pin protects, and that pin
|
|
15
|
+
* stays exactly as it is for AIConversation, AIConversationMessage and
|
|
16
|
+
* AIRunEvent.
|
|
17
|
+
* - CodeFix runs are a SHARED TEAM ARTIFACT: they are triggered off an
|
|
18
|
+
* exception or an incident, they produce a pull request, and their child
|
|
19
|
+
* AIAgentTaskPullRequest rows are already project-readable through the
|
|
20
|
+
* standard CRUD. `userId` on a CodeFix run is attribution only (who
|
|
21
|
+
* clicked "Fix with AI Agent") and is null for automatic triggers — it
|
|
22
|
+
* carries no conversational content.
|
|
23
|
+
*
|
|
24
|
+
* So AIRun cannot use that flat pin. It needs `runType = CodeFix OR userId =
|
|
25
|
+
* <caller>`, a CROSS-COLUMN disjunction, which a query object cannot express
|
|
26
|
+
* (query objects are conjunctions).
|
|
27
|
+
*
|
|
28
|
+
* The clause below is built ENTIRELY from server state and AND-ed onto the
|
|
29
|
+
* caller's query. It never READS query.runType to decide anything — that
|
|
30
|
+
* would be unsound, because onBeforeFind runs BEFORE QueryUtil.serializeQuery,
|
|
31
|
+
* so query.runType here is still a raw, client-controlled operator object
|
|
32
|
+
* whose .value/.toString() are identical across the safe and hostile cases:
|
|
33
|
+
* LessThan("CodeFix") stringifies to exactly "CodeFix" but compiles to
|
|
34
|
+
* `runType < 'CodeFix'`, which matches "Chat". Because the clause is forced, a
|
|
35
|
+
* caller-supplied runType filter can only ever NARROW it, and
|
|
36
|
+
* combineWithPrivacyClause fails closed on operator shapes it does not
|
|
37
|
+
* recognize.
|
|
38
|
+
*
|
|
39
|
+
* Modelled on Utils/Incident/IncidentPrivacyFilter, which solves the same
|
|
40
|
+
* "unrestricted rows for everyone, restricted rows only for their owner"
|
|
41
|
+
* shape.
|
|
42
|
+
*/
|
|
43
|
+
export function getAIRunPrivacyRaw(
|
|
44
|
+
props: DatabaseCommonInteractionProps,
|
|
45
|
+
): FindWhereProperty<any> | undefined {
|
|
46
|
+
if (props.isRoot || props.isMasterAdmin) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/*
|
|
51
|
+
* The same hard gate the flat pin has, and it must stay. A caller with no
|
|
52
|
+
* user — a project API key, which gets userTenantAccessPermission but never
|
|
53
|
+
* userAuthorization (see ProjectAuthorization), so props.userId is
|
|
54
|
+
* undefined — has no personal scope. Today such a caller cannot read AIRun
|
|
55
|
+
* at all. Letting CodeFix rows through here would hand every API key holding
|
|
56
|
+
* ProjectMember the project's whole fix history: access that neither
|
|
57
|
+
* /ai-run nor /code-fix-run grants today. That is a separate product
|
|
58
|
+
* decision and must not ride in as a side effect of this filter.
|
|
59
|
+
*/
|
|
60
|
+
if (!props.userId) {
|
|
61
|
+
throw new NotAuthorizedException(
|
|
62
|
+
"AI runs are personal and can only be accessed by the user who created them.",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const userIdRid: string = "aiRunUid_" + Text.generateRandomText(10);
|
|
67
|
+
const runTypeRid: string = "aiRunType_" + Text.generateRandomText(10);
|
|
68
|
+
|
|
69
|
+
return Raw(
|
|
70
|
+
(alias: string): string => {
|
|
71
|
+
return `(${alias} = :${runTypeRid} OR "AIRun"."userId" = :${userIdRid})`;
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
[runTypeRid]: AIRunType.CodeFix,
|
|
75
|
+
[userIdRid]: props.userId.toString(),
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Applies the clause above on AIRun.runType. Project isolation is unaffected:
|
|
82
|
+
* @TenantColumn("projectId") independently forces projectId = <tenant>, so
|
|
83
|
+
* "CodeFix runs are readable" always means "in YOUR project".
|
|
84
|
+
*/
|
|
85
|
+
export function applyAIRunPrivacyFilter<TQuery>(
|
|
86
|
+
query: TQuery,
|
|
87
|
+
props: DatabaseCommonInteractionProps,
|
|
88
|
+
): TQuery {
|
|
89
|
+
const rawClause: FindWhereProperty<any> | undefined =
|
|
90
|
+
getAIRunPrivacyRaw(props);
|
|
91
|
+
|
|
92
|
+
if (!rawClause) {
|
|
93
|
+
return query;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!query) {
|
|
97
|
+
return { runType: rawClause } as unknown as TQuery;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
(query as any).runType = combineWithPrivacyClause(
|
|
101
|
+
(query as any).runType,
|
|
102
|
+
rawClause,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return query;
|
|
106
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { AIRunEventContentPayload } from "../../../Types/AI/AIChatTypes";
|
|
2
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Write-time caps for AIRunEvent.contentPayload — the run transcript.
|
|
6
|
+
*
|
|
7
|
+
* The transcript exists to debug a bad run, so it stores content verbatim
|
|
8
|
+
* rather than summarized. That makes bounding it a storage requirement, not a
|
|
9
|
+
* nicety: a code-fix agent may read large files and run test suites that emit
|
|
10
|
+
* megabytes, and it does so up to 40 times per run.
|
|
11
|
+
*
|
|
12
|
+
* Only NEW messages are recorded per call (never the whole replayed history),
|
|
13
|
+
* so a run's transcript grows linearly with its turns rather than
|
|
14
|
+
* quadratically. These caps then bound each turn.
|
|
15
|
+
*/
|
|
16
|
+
export const MAX_MESSAGE_CONTENT_CHARS: number = 20000;
|
|
17
|
+
export const MAX_RESPONSE_CONTENT_CHARS: number = 20000;
|
|
18
|
+
export const MAX_TOOL_RESULT_CHARS: number = 20000;
|
|
19
|
+
export const MAX_TOOL_ARGUMENT_CHARS: number = 10000;
|
|
20
|
+
// Belt and braces: a hard ceiling on the serialized payload.
|
|
21
|
+
export const MAX_PAYLOAD_CHARS: number = 200000;
|
|
22
|
+
|
|
23
|
+
const TRUNCATION_SUFFIX: string = "\n… [truncated]";
|
|
24
|
+
|
|
25
|
+
export default class AIRunTranscript {
|
|
26
|
+
/*
|
|
27
|
+
* Clip one string to a cap. Returns the value and whether it was clipped,
|
|
28
|
+
* so the payload can honestly report truncation to the reader rather than
|
|
29
|
+
* silently presenting a partial prompt as complete.
|
|
30
|
+
*/
|
|
31
|
+
public static clip(
|
|
32
|
+
value: string | undefined,
|
|
33
|
+
maxChars: number,
|
|
34
|
+
): { value: string | undefined; isTruncated: boolean } {
|
|
35
|
+
if (value === undefined || value === null) {
|
|
36
|
+
return { value: undefined, isTruncated: false };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (value.length <= maxChars) {
|
|
40
|
+
return { value, isTruncated: false };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
value: value.substring(0, maxChars) + TRUNCATION_SUFFIX,
|
|
45
|
+
isTruncated: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Clip tool arguments by serializing them, so a single huge argument (a
|
|
51
|
+
* write_file `content`, say) cannot blow the row up. Unparseable or
|
|
52
|
+
* oversized arguments degrade to a marker object rather than being dropped
|
|
53
|
+
* — knowing a tool was called with arguments too big to store is itself a
|
|
54
|
+
* useful debugging signal.
|
|
55
|
+
*/
|
|
56
|
+
public static clipArguments(args: JSONObject | undefined): {
|
|
57
|
+
value: JSONObject | undefined;
|
|
58
|
+
isTruncated: boolean;
|
|
59
|
+
} {
|
|
60
|
+
if (!args) {
|
|
61
|
+
return { value: undefined, isTruncated: false };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let serialized: string = "";
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
serialized = JSON.stringify(args);
|
|
68
|
+
} catch {
|
|
69
|
+
return {
|
|
70
|
+
value: { _note: "Arguments could not be serialized." },
|
|
71
|
+
isTruncated: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (serialized.length <= MAX_TOOL_ARGUMENT_CHARS) {
|
|
76
|
+
return { value: args, isTruncated: false };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
value: {
|
|
81
|
+
_note: `Arguments omitted — ${serialized.length} characters exceeds the ${MAX_TOOL_ARGUMENT_CHARS} character cap.`,
|
|
82
|
+
_preview: serialized.substring(0, 2000),
|
|
83
|
+
},
|
|
84
|
+
isTruncated: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* Apply every cap to a payload and stamp isTruncated if anything was
|
|
90
|
+
* clipped. The final MAX_PAYLOAD_CHARS check is a backstop for a payload
|
|
91
|
+
* that is under the per-field caps but still large in aggregate (many
|
|
92
|
+
* messages); it drops the request messages first, since the response and
|
|
93
|
+
* tool result are the more valuable half when debugging.
|
|
94
|
+
*/
|
|
95
|
+
public static clampPayload(
|
|
96
|
+
payload: AIRunEventContentPayload,
|
|
97
|
+
): AIRunEventContentPayload {
|
|
98
|
+
let isTruncated: boolean = payload.isTruncated === true;
|
|
99
|
+
|
|
100
|
+
const clamped: AIRunEventContentPayload = { ...payload };
|
|
101
|
+
|
|
102
|
+
if (payload.requestMessages) {
|
|
103
|
+
clamped.requestMessages = payload.requestMessages.map(
|
|
104
|
+
(message: { role: string; content: string }) => {
|
|
105
|
+
const clipped: { value: string | undefined; isTruncated: boolean } =
|
|
106
|
+
this.clip(message.content, MAX_MESSAGE_CONTENT_CHARS);
|
|
107
|
+
|
|
108
|
+
if (clipped.isTruncated) {
|
|
109
|
+
isTruncated = true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { role: message.role, content: clipped.value || "" };
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (payload.responseContent !== undefined) {
|
|
118
|
+
const clipped: { value: string | undefined; isTruncated: boolean } =
|
|
119
|
+
this.clip(payload.responseContent, MAX_RESPONSE_CONTENT_CHARS);
|
|
120
|
+
clamped.responseContent = clipped.value;
|
|
121
|
+
isTruncated = isTruncated || clipped.isTruncated;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (payload.toolResult !== undefined) {
|
|
125
|
+
const clipped: { value: string | undefined; isTruncated: boolean } =
|
|
126
|
+
this.clip(payload.toolResult, MAX_TOOL_RESULT_CHARS);
|
|
127
|
+
clamped.toolResult = clipped.value;
|
|
128
|
+
isTruncated = isTruncated || clipped.isTruncated;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (payload.responseToolCalls) {
|
|
132
|
+
clamped.responseToolCalls = payload.responseToolCalls.map(
|
|
133
|
+
(toolCall: {
|
|
134
|
+
id?: string | undefined;
|
|
135
|
+
name: string;
|
|
136
|
+
arguments?: JSONObject | undefined;
|
|
137
|
+
}) => {
|
|
138
|
+
const clipped: {
|
|
139
|
+
value: JSONObject | undefined;
|
|
140
|
+
isTruncated: boolean;
|
|
141
|
+
} = this.clipArguments(toolCall.arguments);
|
|
142
|
+
|
|
143
|
+
if (clipped.isTruncated) {
|
|
144
|
+
isTruncated = true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
...(toolCall.id ? { id: toolCall.id } : {}),
|
|
149
|
+
name: toolCall.name,
|
|
150
|
+
...(clipped.value ? { arguments: clipped.value } : {}),
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
* Sacrifice whole fields, largest-payoff first, RE-CHECKING after each —
|
|
158
|
+
* a single pass that drops only requestMessages cannot bound a payload
|
|
159
|
+
* whose bulk is elsewhere. A model that emits 30 write_file calls puts
|
|
160
|
+
* ~10k of arguments each into responseToolCalls, blowing the ceiling while
|
|
161
|
+
* the pass "succeeds" by deleting a two-character user message.
|
|
162
|
+
*
|
|
163
|
+
* Order is by debugging value, cheapest to lose first: the replayed
|
|
164
|
+
* request messages, then the tool arguments (their paths survive in the
|
|
165
|
+
* message), then the tool output. Each step reports what it dropped rather
|
|
166
|
+
* than leaving the reader to wonder.
|
|
167
|
+
*/
|
|
168
|
+
const sacrifices: Array<() => void> = [
|
|
169
|
+
() => {
|
|
170
|
+
const messageCount: number = clamped.requestMessages?.length || 0;
|
|
171
|
+
clamped.requestMessages = [
|
|
172
|
+
{
|
|
173
|
+
role: "system",
|
|
174
|
+
content: `[${messageCount} request message(s) omitted — this step's transcript exceeded the ${MAX_PAYLOAD_CHARS} character cap.]`,
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
},
|
|
178
|
+
() => {
|
|
179
|
+
if (!clamped.responseToolCalls) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
clamped.responseToolCalls = clamped.responseToolCalls.map(
|
|
184
|
+
(toolCall: {
|
|
185
|
+
id?: string | undefined;
|
|
186
|
+
name: string;
|
|
187
|
+
arguments?: JSONObject | undefined;
|
|
188
|
+
}) => {
|
|
189
|
+
return {
|
|
190
|
+
...(toolCall.id ? { id: toolCall.id } : {}),
|
|
191
|
+
name: toolCall.name,
|
|
192
|
+
arguments: {
|
|
193
|
+
_note: `Arguments omitted — this step's transcript exceeded the ${MAX_PAYLOAD_CHARS} character cap.`,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
);
|
|
198
|
+
},
|
|
199
|
+
() => {
|
|
200
|
+
clamped.toolResult = `[Tool output omitted — this step's transcript exceeded the ${MAX_PAYLOAD_CHARS} character cap.]`;
|
|
201
|
+
},
|
|
202
|
+
() => {
|
|
203
|
+
clamped.responseContent = `[Model response omitted — this step's transcript exceeded the ${MAX_PAYLOAD_CHARS} character cap.]`;
|
|
204
|
+
},
|
|
205
|
+
/*
|
|
206
|
+
* Last resort: responseToolCalls has no bounded LENGTH, only bounded
|
|
207
|
+
* entries, so a response with enough calls stays over cap even with every
|
|
208
|
+
* argument already dropped. Collapse it to a count.
|
|
209
|
+
*/
|
|
210
|
+
() => {
|
|
211
|
+
const toolCallCount: number = clamped.responseToolCalls?.length || 0;
|
|
212
|
+
delete clamped.responseToolCalls;
|
|
213
|
+
clamped.responseContent = `[${toolCallCount} tool call(s) and this step's content omitted — the transcript exceeded the ${MAX_PAYLOAD_CHARS} character cap.]`;
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
for (const sacrifice of sacrifices) {
|
|
218
|
+
if (this.serializedLength(clamped) <= MAX_PAYLOAD_CHARS) {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
sacrifice();
|
|
223
|
+
isTruncated = true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (isTruncated) {
|
|
227
|
+
clamped.isTruncated = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return clamped;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private static serializedLength(payload: AIRunEventContentPayload): number {
|
|
234
|
+
try {
|
|
235
|
+
return JSON.stringify(payload).length;
|
|
236
|
+
} catch {
|
|
237
|
+
return Number.MAX_SAFE_INTEGER;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -7,6 +7,7 @@ import { JSONObject } from "../../../../Types/JSON";
|
|
|
7
7
|
import ObjectID from "../../../../Types/ObjectID";
|
|
8
8
|
import AIChatMessageRole from "../../../../Types/AI/AIChatMessageRole";
|
|
9
9
|
import AIChatMessageStatus from "../../../../Types/AI/AIChatMessageStatus";
|
|
10
|
+
import { AIChatPageContext } from "../../../../Types/AI/AIChatPageContext";
|
|
10
11
|
import AIChatPermissionMode from "../../../../Types/AI/AIChatPermissionMode";
|
|
11
12
|
import AIRunEventType from "../../../../Types/AI/AIRunEventType";
|
|
12
13
|
import AIRunStatus from "../../../../Types/AI/AIRunStatus";
|
|
@@ -43,6 +44,13 @@ export interface ChatTurnRequest {
|
|
|
43
44
|
llmProviderId?: ObjectID | undefined;
|
|
44
45
|
// How much autonomy the agent has to run mutating tools in this conversation.
|
|
45
46
|
permissionMode: AIChatPermissionMode;
|
|
47
|
+
/*
|
|
48
|
+
* What the user was looking at in the dashboard when they sent this message
|
|
49
|
+
* (already sanitized by the API). Folded into the system prompt so "this
|
|
50
|
+
* incident" resolves to the entity on screen. Per-turn: not persisted, and
|
|
51
|
+
* not needed on resume (the paused state already contains the built prompt).
|
|
52
|
+
*/
|
|
53
|
+
pageContext?: AIChatPageContext | undefined;
|
|
46
54
|
// The requesting user's real permission props, captured at request time.
|
|
47
55
|
props: DatabaseCommonInteractionProps;
|
|
48
56
|
}
|
|
@@ -891,6 +899,7 @@ export default class ChatAgentRunner {
|
|
|
891
899
|
content: buildObservabilityChatSystemPrompt({
|
|
892
900
|
currentTime: OneUptimeDate.getCurrentDate(),
|
|
893
901
|
permissionMode: request.permissionMode,
|
|
902
|
+
pageContext: request.pageContext,
|
|
894
903
|
}),
|
|
895
904
|
},
|
|
896
905
|
];
|