@oneuptime/common 11.3.24 → 11.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +322 -0
  2. package/Models/DatabaseModels/AIConversationMessage.ts +495 -0
  3. package/Models/DatabaseModels/AIRun.ts +584 -0
  4. package/Models/DatabaseModels/AIRunEvent.ts +443 -0
  5. package/Models/DatabaseModels/Index.ts +8 -0
  6. package/Models/DatabaseModels/LlmLog.ts +26 -0
  7. package/Models/DatabaseModels/LlmProvider.ts +2 -2
  8. package/Server/API/AIChatAPI.ts +693 -0
  9. package/Server/API/LlmProviderAPI.ts +169 -0
  10. package/Server/API/MicrosoftTeamsAPI.ts +5 -0
  11. package/Server/API/SlackAPI.ts +663 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.ts +245 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.ts +36 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.ts +46 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.ts +119 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  17. package/Server/Services/AIConversationMessageService.ts +39 -0
  18. package/Server/Services/AIConversationService.ts +63 -0
  19. package/Server/Services/AIRunEventService.ts +39 -0
  20. package/Server/Services/AIRunService.ts +39 -0
  21. package/Server/Services/AIService.ts +53 -31
  22. package/Server/Services/DatabaseService.ts +19 -0
  23. package/Server/Services/LlmProviderService.ts +110 -0
  24. package/Server/Services/ProjectService.ts +24 -0
  25. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +74 -9
  26. package/Server/Utils/AI/AIChatPrivacyFilter.ts +28 -0
  27. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +1054 -0
  28. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +239 -0
  29. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +51 -0
  30. package/Server/Utils/AI/Toolbox/AlertTools.ts +201 -0
  31. package/Server/Utils/AI/Toolbox/AlertWriteTools.ts +174 -0
  32. package/Server/Utils/AI/Toolbox/ContextTools.ts +189 -0
  33. package/Server/Utils/AI/Toolbox/ExceptionTools.ts +149 -0
  34. package/Server/Utils/AI/Toolbox/IncidentTools.ts +204 -0
  35. package/Server/Utils/AI/Toolbox/IncidentWriteTools.ts +350 -0
  36. package/Server/Utils/AI/Toolbox/Index.ts +228 -0
  37. package/Server/Utils/AI/Toolbox/LogTools.ts +339 -0
  38. package/Server/Utils/AI/Toolbox/MetricTools.ts +179 -0
  39. package/Server/Utils/AI/Toolbox/MonitorTools.ts +193 -0
  40. package/Server/Utils/AI/Toolbox/Serializer.ts +257 -0
  41. package/Server/Utils/AI/Toolbox/ToolTypes.ts +249 -0
  42. package/Server/Utils/AI/Toolbox/TraceTools.ts +402 -0
  43. package/Server/Utils/AI/Toolbox/WidgetBuilder.ts +189 -0
  44. package/Server/Utils/LLM/LLMService.ts +502 -92
  45. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +512 -19
  46. package/Server/Utils/Workspace/Slack/Slack.ts +80 -0
  47. package/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  48. package/Tests/Server/Utils/AI/AIChatModelACL.test.ts +42 -0
  49. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +89 -0
  50. package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +139 -0
  51. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +308 -0
  52. package/Tests/Server/Utils/AI/ToolArgsGetTimeRange.test.ts +62 -0
  53. package/Tests/Server/Utils/AI/ToolArgsScopeServiceIds.test.ts +79 -0
  54. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +155 -0
  55. package/Tests/Types/Billing/SubscriptionStatus.test.ts +127 -0
  56. package/Tests/Types/Metrics/RecordingRuleDefinition.test.ts +213 -0
  57. package/Types/AI/AIChatMessageRole.ts +6 -0
  58. package/Types/AI/AIChatMessageStatus.ts +32 -0
  59. package/Types/AI/AIChatPermissionMode.ts +69 -0
  60. package/Types/AI/AIChatTypes.ts +231 -0
  61. package/Types/AI/AIRunEventType.ts +17 -0
  62. package/Types/AI/AIRunStatus.ts +28 -0
  63. package/Types/AI/AIRunType.ts +6 -0
  64. package/Types/LLM/LlmType.ts +6 -0
  65. package/UI/Components/Header/HeaderIconDropdownButton.tsx +22 -12
  66. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +35 -3
  67. package/UI/Components/Page/Page.tsx +14 -0
  68. package/UI/Utils/LlmTypeDropdownOptions.ts +40 -0
  69. package/UI/Utils/TestLLMProvider.ts +59 -0
  70. package/build/dist/Models/DatabaseModels/AIConversation.js +345 -0
  71. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -0
  72. package/build/dist/Models/DatabaseModels/AIConversationMessage.js +521 -0
  73. package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -0
  74. package/build/dist/Models/DatabaseModels/AIRun.js +619 -0
  75. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -0
  76. package/build/dist/Models/DatabaseModels/AIRunEvent.js +469 -0
  77. package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -0
  78. package/build/dist/Models/DatabaseModels/Index.js +8 -0
  79. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  80. package/build/dist/Models/DatabaseModels/LlmLog.js +28 -0
  81. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  82. package/build/dist/Models/DatabaseModels/LlmProvider.js +2 -2
  83. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  84. package/build/dist/Server/API/AIChatAPI.js +498 -0
  85. package/build/dist/Server/API/AIChatAPI.js.map +1 -0
  86. package/build/dist/Server/API/LlmProviderAPI.js +107 -1
  87. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  88. package/build/dist/Server/API/MicrosoftTeamsAPI.js +4 -0
  89. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  90. package/build/dist/Server/API/SlackAPI.js +442 -0
  91. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  92. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js +96 -0
  93. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js.map +1 -0
  94. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js +25 -0
  95. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js.map +1 -0
  96. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js +31 -0
  97. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js.map +1 -0
  98. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js +46 -0
  99. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js.map +1 -0
  100. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  101. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  102. package/build/dist/Server/Services/AIConversationMessageService.js +34 -0
  103. package/build/dist/Server/Services/AIConversationMessageService.js.map +1 -0
  104. package/build/dist/Server/Services/AIConversationService.js +42 -0
  105. package/build/dist/Server/Services/AIConversationService.js.map +1 -0
  106. package/build/dist/Server/Services/AIRunEventService.js +34 -0
  107. package/build/dist/Server/Services/AIRunEventService.js.map +1 -0
  108. package/build/dist/Server/Services/AIRunService.js +34 -0
  109. package/build/dist/Server/Services/AIRunService.js.map +1 -0
  110. package/build/dist/Server/Services/AIService.js +31 -23
  111. package/build/dist/Server/Services/AIService.js.map +1 -1
  112. package/build/dist/Server/Services/DatabaseService.js +10 -0
  113. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  114. package/build/dist/Server/Services/LlmProviderService.js +108 -0
  115. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  116. package/build/dist/Server/Services/ProjectService.js +25 -0
  117. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  118. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +50 -7
  119. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  120. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +18 -0
  121. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -0
  122. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +745 -0
  123. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -0
  124. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +165 -0
  125. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -0
  126. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +44 -0
  127. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -0
  128. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +167 -0
  129. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -0
  130. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js +136 -0
  131. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js.map +1 -0
  132. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js +141 -0
  133. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js.map +1 -0
  134. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js +117 -0
  135. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js.map +1 -0
  136. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +167 -0
  137. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -0
  138. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js +280 -0
  139. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js.map +1 -0
  140. package/build/dist/Server/Utils/AI/Toolbox/Index.js +150 -0
  141. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -0
  142. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js +246 -0
  143. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js.map +1 -0
  144. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +120 -0
  145. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -0
  146. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +158 -0
  147. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -0
  148. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +188 -0
  149. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -0
  150. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js +142 -0
  151. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js.map +1 -0
  152. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js +309 -0
  153. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js.map +1 -0
  154. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js +120 -0
  155. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js.map +1 -0
  156. package/build/dist/Server/Utils/LLM/LLMService.js +372 -88
  157. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  158. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +378 -15
  159. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  160. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +59 -0
  161. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  162. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  163. package/build/dist/Types/AI/AIChatMessageRole.js +7 -0
  164. package/build/dist/Types/AI/AIChatMessageRole.js.map +1 -0
  165. package/build/dist/Types/AI/AIChatMessageStatus.js +27 -0
  166. package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -0
  167. package/build/dist/Types/AI/AIChatPermissionMode.js +53 -0
  168. package/build/dist/Types/AI/AIChatPermissionMode.js.map +1 -0
  169. package/build/dist/Types/AI/AIChatTypes.js +74 -0
  170. package/build/dist/Types/AI/AIChatTypes.js.map +1 -0
  171. package/build/dist/Types/AI/AIRunEventType.js +18 -0
  172. package/build/dist/Types/AI/AIRunEventType.js.map +1 -0
  173. package/build/dist/Types/AI/AIRunStatus.js +26 -0
  174. package/build/dist/Types/AI/AIRunStatus.js.map +1 -0
  175. package/build/dist/Types/AI/AIRunType.js +7 -0
  176. package/build/dist/Types/AI/AIRunType.js.map +1 -0
  177. package/build/dist/Types/LLM/LlmType.js +6 -0
  178. package/build/dist/Types/LLM/LlmType.js.map +1 -1
  179. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +10 -5
  180. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  181. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +18 -4
  182. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  183. package/build/dist/UI/Components/Page/Page.js +3 -1
  184. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  185. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js +38 -0
  186. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js.map +1 -0
  187. package/build/dist/UI/Utils/TestLLMProvider.js +37 -0
  188. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -0
  189. package/package.json +1 -1
@@ -0,0 +1,246 @@
1
+ import Log from "../../../../Models/AnalyticsModels/Log";
2
+ import DatabaseRequestType from "../../../Types/BaseDatabase/DatabaseRequestType";
3
+ import ModelPermission from "../../../Types/AnalyticsDatabase/ModelPermission";
4
+ import InBetween from "../../../../Types/BaseDatabase/InBetween";
5
+ import Includes from "../../../../Types/BaseDatabase/Includes";
6
+ import Search from "../../../../Types/BaseDatabase/Search";
7
+ import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
8
+ import Permission from "../../../../Types/Permission";
9
+ import { AIChatCitationTargetType, } from "../../../../Types/AI/AIChatTypes";
10
+ import LogService from "../../../Services/LogService";
11
+ import LogAggregationService from "../../../Services/LogAggregationService";
12
+ import ToolResultSerializer from "./Serializer";
13
+ import WidgetBuilder from "./WidgetBuilder";
14
+ import { TimeRangeSchemaProperties, ToolArgs, } from "./ToolTypes";
15
+ // Keep pivoted histogram rows under the serializer's 50-row cap.
16
+ const MAX_HISTOGRAM_BUCKETS = 48;
17
+ const LOG_READ_PERMISSIONS = [
18
+ Permission.ProjectOwner,
19
+ Permission.ProjectAdmin,
20
+ Permission.ProjectMember,
21
+ Permission.Viewer,
22
+ Permission.TelemetryAdmin,
23
+ Permission.TelemetryMember,
24
+ Permission.TelemetryViewer,
25
+ Permission.ReadTelemetryServiceLog,
26
+ ];
27
+ export const SearchLogsTool = {
28
+ name: "search_logs",
29
+ description: "Search raw log lines. Filter by time range, severity, body text, trace ID or service. Returns the most recent matching lines. Always pass an explicit time range when investigating a specific window.",
30
+ inputSchema: {
31
+ type: "object",
32
+ properties: Object.assign(Object.assign({}, TimeRangeSchemaProperties), { severityTexts: {
33
+ type: "array",
34
+ items: { type: "string" },
35
+ description: 'Filter by severity, e.g. ["Error", "Fatal"] or ["Warn"].',
36
+ }, bodySearchText: {
37
+ type: "string",
38
+ description: "Only logs whose body contains this text.",
39
+ }, traceId: {
40
+ type: "string",
41
+ description: "Only logs belonging to this trace.",
42
+ }, serviceId: {
43
+ type: "string",
44
+ description: "Only logs from this telemetry service (resolve names via lookup_context first).",
45
+ }, limit: {
46
+ type: "number",
47
+ description: "Maximum log lines to return (default 25, max 50).",
48
+ } }),
49
+ },
50
+ requiredPermissions: LOG_READ_PERMISSIONS,
51
+ execute: async (args, ctx) => {
52
+ const { startTime, endTime } = ToolArgs.getTimeRange(args, {
53
+ defaultHours: 1,
54
+ maxDays: 30,
55
+ });
56
+ const limit = ToolArgs.getNumber(args, "limit", {
57
+ defaultValue: 25,
58
+ min: 1,
59
+ max: 50,
60
+ });
61
+ const query = {
62
+ time: new InBetween(startTime, endTime),
63
+ };
64
+ const severityTexts = ToolArgs.getStringArray(args, "severityTexts");
65
+ if (severityTexts) {
66
+ query["severityText"] = new Includes(severityTexts);
67
+ }
68
+ const bodySearchText = ToolArgs.getString(args, "bodySearchText");
69
+ if (bodySearchText) {
70
+ query["body"] = new Search(bodySearchText);
71
+ }
72
+ const traceId = ToolArgs.getString(args, "traceId");
73
+ if (traceId) {
74
+ query["traceId"] = traceId;
75
+ }
76
+ const serviceId = ToolArgs.getObjectID(args, "serviceId");
77
+ if (serviceId) {
78
+ query["primaryEntityId"] = serviceId;
79
+ }
80
+ const logs = await LogService.findBy({
81
+ query: query,
82
+ select: {
83
+ time: true,
84
+ severityText: true,
85
+ body: true,
86
+ traceId: true,
87
+ spanId: true,
88
+ primaryEntityId: true,
89
+ },
90
+ sort: {
91
+ time: SortOrder.Descending,
92
+ },
93
+ limit: limit,
94
+ skip: 0,
95
+ props: ctx.props,
96
+ });
97
+ const rows = logs.map((log) => {
98
+ return {
99
+ time: log.time,
100
+ severity: log.severityText,
101
+ body: log.body,
102
+ traceId: log.traceId,
103
+ spanId: log.spanId,
104
+ };
105
+ });
106
+ const serialized = ToolResultSerializer.serializeRows(rows);
107
+ const logsLink = {
108
+ type: AIChatCitationTargetType.Logs,
109
+ };
110
+ return {
111
+ dataForLlm: serialized.text,
112
+ rowCount: serialized.rowCount,
113
+ citationLabel: `Logs ${startTime.toISOString()} – ${endTime.toISOString()} (${serialized.rowCount} shown)`,
114
+ citationTarget: logsLink,
115
+ redactionCount: serialized.redactionCount,
116
+ isTruncated: serialized.isTruncated,
117
+ widget: rows.length > 0
118
+ ? WidgetBuilder.table({
119
+ title: `Logs (${rows.length})`,
120
+ description: `${startTime.toISOString()} – ${endTime.toISOString()}`,
121
+ columns: [
122
+ { key: "time", title: "Time", type: "date" },
123
+ { key: "severity", title: "Severity", type: "text" },
124
+ { key: "body", title: "Message", type: "text" },
125
+ { key: "traceId", title: "Trace", type: "text" },
126
+ ],
127
+ rows: rows,
128
+ link: logsLink,
129
+ })
130
+ : undefined,
131
+ };
132
+ },
133
+ };
134
+ export const LogHistogramTool = {
135
+ name: "log_histogram",
136
+ description: "Get log volume over time, split by severity. Use this to spot error spikes and quiet periods before drilling into raw logs.",
137
+ inputSchema: {
138
+ type: "object",
139
+ properties: Object.assign(Object.assign({}, TimeRangeSchemaProperties), { severityTexts: {
140
+ type: "array",
141
+ items: { type: "string" },
142
+ description: "Filter to these severities before bucketing.",
143
+ }, bodySearchText: {
144
+ type: "string",
145
+ description: "Only count logs whose body contains this text.",
146
+ }, serviceId: {
147
+ type: "string",
148
+ description: "Only logs from this telemetry service.",
149
+ } }),
150
+ },
151
+ requiredPermissions: LOG_READ_PERMISSIONS,
152
+ execute: async (args, ctx) => {
153
+ const { startTime, endTime } = ToolArgs.getTimeRange(args, {
154
+ defaultHours: 24,
155
+ maxDays: 30,
156
+ });
157
+ const windowMinutes = (endTime.getTime() - startTime.getTime()) / (60 * 1000);
158
+ /*
159
+ * Bound the number of time buckets. getHistogram returns one row per
160
+ * (bucket, severity); after we pivot to one row per bucket that is at most
161
+ * MAX_HISTOGRAM_BUCKETS rows, which stays under the serializer's row cap so
162
+ * the most recent buckets are never dropped (spike detection reads the tail
163
+ * of the window).
164
+ */
165
+ const bucketSizeInMinutes = Math.max(1, Math.ceil(windowMinutes / MAX_HISTOGRAM_BUCKETS));
166
+ const serviceId = ToolArgs.getObjectID(args, "serviceId");
167
+ /*
168
+ * getHistogram builds raw aggregation SQL and skips the model layer's
169
+ * owned-scope filter, so a label-restricted user would otherwise see
170
+ * project-wide volume. Constrain to the services this user may read.
171
+ */
172
+ const accessibleServiceIds = await ModelPermission.getAccessibleServiceIdsForAnalyticsModel(Log, ctx.props, DatabaseRequestType.Read);
173
+ const buckets = await LogAggregationService.getHistogram({
174
+ projectId: ctx.projectId,
175
+ startTime: startTime,
176
+ endTime: endTime,
177
+ bucketSizeInMinutes: bucketSizeInMinutes,
178
+ severityTexts: ToolArgs.getStringArray(args, "severityTexts"),
179
+ bodySearchText: ToolArgs.getString(args, "bodySearchText"),
180
+ serviceIds: ToolArgs.scopeServiceIds(accessibleServiceIds, serviceId),
181
+ });
182
+ /*
183
+ * Pivot (time, severity, count) rows into one row per time bucket with a
184
+ * column per severity, e.g. "time=… | Error=12 | Warn=3". This is both more
185
+ * compact for the model and collapses the row count from
186
+ * buckets×severities down to just buckets.
187
+ */
188
+ const rowsByTime = new Map();
189
+ for (const bucket of buckets) {
190
+ let row = rowsByTime.get(bucket.time);
191
+ if (!row) {
192
+ row = { time: bucket.time };
193
+ rowsByTime.set(bucket.time, row);
194
+ }
195
+ row[bucket.severity || "Unspecified"] = bucket.count;
196
+ }
197
+ const rows = Array.from(rowsByTime.values()).sort((a, b) => {
198
+ return String(a["time"]).localeCompare(String(b["time"]));
199
+ });
200
+ const serialized = ToolResultSerializer.serializeRows(rows);
201
+ /*
202
+ * Pivot the per-bucket rows into one series per severity so the widget can
203
+ * render a stacked bar chart (Error on top of Warn on top of Info, etc).
204
+ */
205
+ const severityKeys = Array.from(new Set(rows.flatMap((row) => {
206
+ return Object.keys(row).filter((key) => {
207
+ return key !== "time";
208
+ });
209
+ })));
210
+ const series = severityKeys.map((severity) => {
211
+ return {
212
+ name: severity,
213
+ points: rows.map((row) => {
214
+ return {
215
+ x: String(row["time"]),
216
+ y: typeof row[severity] === "number"
217
+ ? row[severity]
218
+ : 0,
219
+ };
220
+ }),
221
+ };
222
+ });
223
+ return {
224
+ dataForLlm: serialized.text,
225
+ rowCount: serialized.rowCount,
226
+ citationLabel: `Log volume by severity, ${startTime.toISOString()} – ${endTime.toISOString()}`,
227
+ citationTarget: {
228
+ type: AIChatCitationTargetType.Logs,
229
+ },
230
+ redactionCount: serialized.redactionCount,
231
+ isTruncated: serialized.isTruncated,
232
+ widget: series.length > 0 && rows.length > 0
233
+ ? WidgetBuilder.bars({
234
+ title: "Log volume by severity",
235
+ description: `${startTime.toISOString()} – ${endTime.toISOString()}`,
236
+ series: series,
237
+ stacked: true,
238
+ xIsTime: true,
239
+ unit: "logs",
240
+ link: { type: AIChatCitationTargetType.Logs },
241
+ })
242
+ : undefined,
243
+ };
244
+ },
245
+ };
246
+ //# sourceMappingURL=LogTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogTools.js","sourceRoot":"","sources":["../../../../../../Server/Utils/AI/Toolbox/LogTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import AggregationType from "../../../../Types/BaseDatabase/AggregationType";
2
+ import InBetween from "../../../../Types/BaseDatabase/InBetween";
3
+ import Permission from "../../../../Types/Permission";
4
+ import BadDataException from "../../../../Types/Exception/BadDataException";
5
+ import { AIChatCitationTargetType, } from "../../../../Types/AI/AIChatTypes";
6
+ import MetricService from "../../../Services/MetricService";
7
+ import ToolResultSerializer from "./Serializer";
8
+ import WidgetBuilder from "./WidgetBuilder";
9
+ import OneUptimeDate from "../../../../Types/Date";
10
+ import { TimeRangeSchemaProperties, ToolArgs, } from "./ToolTypes";
11
+ /*
12
+ * Note: metric read access is gated on ReadTelemetryServiceTraces — this
13
+ * mirrors the guard on the dashboard's /telemetry/metrics/* routes.
14
+ */
15
+ const METRIC_READ_PERMISSIONS = [
16
+ Permission.ProjectOwner,
17
+ Permission.ProjectAdmin,
18
+ Permission.ProjectMember,
19
+ Permission.Viewer,
20
+ Permission.TelemetryAdmin,
21
+ Permission.TelemetryMember,
22
+ Permission.TelemetryViewer,
23
+ Permission.ReadTelemetryServiceTraces,
24
+ ];
25
+ export const QueryMetricsTool = {
26
+ name: "query_metrics",
27
+ description: "Aggregate a metric over time: Avg, Max, Min, Sum, Count or P50/P90/P95/P99 percentiles (histogram-aware). Requires the exact metric name — discover names via lookup_context. Monitor metrics use reserved names like oneuptime.monitor.response.time with the monitor's ID as entityId.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: Object.assign(Object.assign({}, TimeRangeSchemaProperties), { metricName: {
31
+ type: "string",
32
+ description: "Exact metric name (required).",
33
+ }, aggregationType: {
34
+ type: "string",
35
+ enum: ["Avg", "Max", "Min", "Sum", "Count", "P50", "P90", "P95", "P99"],
36
+ description: "How to aggregate (default Avg).",
37
+ }, entityId: {
38
+ type: "string",
39
+ description: "Only data points from this service/host/monitor (its OneUptime ID).",
40
+ } }),
41
+ required: ["metricName"],
42
+ },
43
+ requiredPermissions: METRIC_READ_PERMISSIONS,
44
+ execute: async (args, ctx) => {
45
+ const metricName = ToolArgs.getString(args, "metricName");
46
+ if (!metricName) {
47
+ throw new BadDataException("metricName is required. Use lookup_context with type 'metricNames' to discover metric names.");
48
+ }
49
+ const { startTime, endTime } = ToolArgs.getTimeRange(args, {
50
+ defaultHours: 24,
51
+ maxDays: 30,
52
+ });
53
+ const aggregationTypeString = ToolArgs.getString(args, "aggregationType") || "Avg";
54
+ if (!Object.values(AggregationType).includes(aggregationTypeString)) {
55
+ throw new BadDataException(`Invalid aggregationType: ${aggregationTypeString}`);
56
+ }
57
+ /*
58
+ * The time filter must be part of the query's WHERE clause. aggregateBy's
59
+ * startTimestamp/endTimestamp only define the bucket grid — without an
60
+ * explicit `time` filter the percentile/aggregate scans the metric's whole
61
+ * retention and mixes in data outside the requested window.
62
+ */
63
+ const query = {
64
+ name: metricName,
65
+ time: new InBetween(startTime, endTime),
66
+ };
67
+ const entityId = ToolArgs.getObjectID(args, "entityId");
68
+ if (entityId) {
69
+ query["primaryEntityId"] = entityId;
70
+ }
71
+ const aggregateBy = {
72
+ aggregateColumnName: "value",
73
+ aggregationType: aggregationTypeString,
74
+ aggregationTimestampColumnName: "time",
75
+ startTimestamp: startTime,
76
+ endTimestamp: endTime,
77
+ query: query,
78
+ limit: 200,
79
+ skip: 0,
80
+ props: ctx.props,
81
+ };
82
+ const result = await MetricService.aggregateBy(aggregateBy);
83
+ const rows = result.data.map((item) => {
84
+ return {
85
+ timestamp: item.timestamp,
86
+ value: item.value,
87
+ };
88
+ });
89
+ const serialized = ToolResultSerializer.serializeRows(rows);
90
+ const points = result.data.map((item) => {
91
+ return {
92
+ x: OneUptimeDate.toString(OneUptimeDate.fromString(item.timestamp)),
93
+ y: typeof item.value === "number" ? item.value : null,
94
+ };
95
+ });
96
+ const seriesName = entityId
97
+ ? `${aggregationTypeString}(${metricName}) · ${entityId.toString()}`
98
+ : `${aggregationTypeString}(${metricName})`;
99
+ return {
100
+ dataForLlm: serialized.text,
101
+ rowCount: serialized.rowCount,
102
+ citationLabel: `${aggregationTypeString}(${metricName}), ${startTime.toISOString()} – ${endTime.toISOString()}`,
103
+ citationTarget: {
104
+ type: AIChatCitationTargetType.Metrics,
105
+ },
106
+ redactionCount: serialized.redactionCount,
107
+ isTruncated: serialized.isTruncated,
108
+ widget: points.length > 0
109
+ ? WidgetBuilder.timeSeries({
110
+ title: `${aggregationTypeString} of ${metricName}`,
111
+ description: `${startTime.toISOString()} – ${endTime.toISOString()}`,
112
+ series: [{ name: seriesName, points: points }],
113
+ valueLabel: aggregationTypeString,
114
+ link: { type: AIChatCitationTargetType.Metrics },
115
+ })
116
+ : undefined,
117
+ };
118
+ },
119
+ };
120
+ //# sourceMappingURL=MetricTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetricTools.js","sourceRoot":"","sources":["../../../../../../Server/Utils/AI/Toolbox/MetricTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
2
+ import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
3
+ import { AIChatCitationTargetType } from "../../../../Types/AI/AIChatTypes";
4
+ import MonitorService from "../../../Services/MonitorService";
5
+ import MonitorStatusTimelineService from "../../../Services/MonitorStatusTimelineService";
6
+ import QueryHelper from "../../../Types/Database/QueryHelper";
7
+ import ToolResultSerializer from "./Serializer";
8
+ import { ToolArgs, } from "./ToolTypes";
9
+ /*
10
+ * Derived from the model ACL so the tool gate can never drift from RBAC.
11
+ * Resolved lazily rather than at module load: this module is pulled in through
12
+ * the service import graph before the Monitor model class is fully wired up,
13
+ * so calling a model method at import time throws a circular-dependency
14
+ * TypeError. By the time a tool actually executes, every module is loaded.
15
+ */
16
+ let cachedReadPermissions = null;
17
+ const resolveReadPermissions = () => {
18
+ if (!cachedReadPermissions) {
19
+ cachedReadPermissions = new Monitor().getReadPermissions();
20
+ }
21
+ return cachedReadPermissions;
22
+ };
23
+ export const QueryMonitorsTool = {
24
+ name: "query_monitors",
25
+ description: "List monitors in this project with their current status. Pass monitorId to also get that monitor's recent status timeline (when it went up or down).",
26
+ inputSchema: {
27
+ type: "object",
28
+ properties: {
29
+ monitorId: {
30
+ type: "string",
31
+ description: "Get one monitor by its ID, including its recent status timeline.",
32
+ },
33
+ nameSearch: {
34
+ type: "string",
35
+ description: "Filter monitors whose name contains this text.",
36
+ },
37
+ limit: {
38
+ type: "number",
39
+ description: "Maximum monitors to return (default 25, max 50).",
40
+ },
41
+ },
42
+ },
43
+ get requiredPermissions() {
44
+ return resolveReadPermissions();
45
+ },
46
+ execute: async (args, ctx) => {
47
+ var _a, _b, _c;
48
+ const monitorId = ToolArgs.getObjectID(args, "monitorId");
49
+ if (monitorId) {
50
+ const monitor = await MonitorService.findOneById({
51
+ id: monitorId,
52
+ select: {
53
+ _id: true,
54
+ name: true,
55
+ monitorType: true,
56
+ currentMonitorStatus: {
57
+ name: true,
58
+ },
59
+ },
60
+ props: ctx.props,
61
+ });
62
+ const timeline = await MonitorStatusTimelineService.findBy({
63
+ query: {
64
+ monitorId: monitorId,
65
+ },
66
+ select: {
67
+ createdAt: true,
68
+ monitorStatus: {
69
+ name: true,
70
+ },
71
+ },
72
+ sort: {
73
+ createdAt: SortOrder.Descending,
74
+ },
75
+ limit: 20,
76
+ skip: 0,
77
+ props: ctx.props,
78
+ });
79
+ const rows = [];
80
+ if (monitor) {
81
+ rows.push({
82
+ record: "monitor",
83
+ id: (_a = monitor.id) === null || _a === void 0 ? void 0 : _a.toString(),
84
+ name: monitor.name,
85
+ type: monitor.monitorType,
86
+ currentStatus: (_b = monitor.currentMonitorStatus) === null || _b === void 0 ? void 0 : _b.name,
87
+ });
88
+ }
89
+ for (const item of timeline) {
90
+ rows.push({
91
+ record: "statusChange",
92
+ status: (_c = item.monitorStatus) === null || _c === void 0 ? void 0 : _c.name,
93
+ at: item.createdAt,
94
+ });
95
+ }
96
+ const serialized = ToolResultSerializer.serializeRows(rows);
97
+ return {
98
+ dataForLlm: serialized.text,
99
+ rowCount: serialized.rowCount,
100
+ citationLabel: `Monitor ${(monitor === null || monitor === void 0 ? void 0 : monitor.name) || monitorId.toString()} + status timeline`,
101
+ citationTarget: {
102
+ type: AIChatCitationTargetType.MonitorView,
103
+ params: { monitorId: monitorId.toString() },
104
+ },
105
+ redactionCount: serialized.redactionCount,
106
+ isTruncated: serialized.isTruncated,
107
+ };
108
+ }
109
+ const limit = ToolArgs.getNumber(args, "limit", {
110
+ defaultValue: 25,
111
+ min: 1,
112
+ max: 50,
113
+ });
114
+ const nameSearch = ToolArgs.getString(args, "nameSearch");
115
+ const monitors = await MonitorService.findBy({
116
+ query: nameSearch
117
+ ? {
118
+ name: QueryHelper.search(nameSearch),
119
+ }
120
+ : {},
121
+ select: {
122
+ _id: true,
123
+ name: true,
124
+ monitorType: true,
125
+ currentMonitorStatus: {
126
+ name: true,
127
+ },
128
+ },
129
+ sort: {
130
+ name: SortOrder.Ascending,
131
+ },
132
+ limit: limit,
133
+ skip: 0,
134
+ props: ctx.props,
135
+ });
136
+ const rows = monitors.map((monitor) => {
137
+ var _a, _b;
138
+ return {
139
+ id: (_a = monitor.id) === null || _a === void 0 ? void 0 : _a.toString(),
140
+ name: monitor.name,
141
+ type: monitor.monitorType,
142
+ currentStatus: (_b = monitor.currentMonitorStatus) === null || _b === void 0 ? void 0 : _b.name,
143
+ };
144
+ });
145
+ const serialized = ToolResultSerializer.serializeRows(rows);
146
+ return {
147
+ dataForLlm: serialized.text,
148
+ rowCount: serialized.rowCount,
149
+ citationLabel: `Monitors (${serialized.rowCount} found)`,
150
+ citationTarget: {
151
+ type: AIChatCitationTargetType.Monitors,
152
+ },
153
+ redactionCount: serialized.redactionCount,
154
+ isTruncated: serialized.isTruncated,
155
+ };
156
+ },
157
+ };
158
+ //# sourceMappingURL=MonitorTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonitorTools.js","sourceRoot":"","sources":["../../../../../../Server/Utils/AI/Toolbox/MonitorTools.ts"],"names":[],"mappings":"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"}