@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
@@ -39,6 +39,7 @@ import MicrosoftTeamsIncidentEpisodeActions from "./Actions/IncidentEpisode";
39
39
  import MicrosoftTeamsMonitorActions from "./Actions/Monitor";
40
40
  import MicrosoftTeamsScheduledMaintenanceActions from "./Actions/ScheduledMaintenance";
41
41
  import MicrosoftTeamsOnCallDutyActions from "./Actions/OnCallDutyPolicy";
42
+ import AccessTokenService from "../../../Services/AccessTokenService";
42
43
  // Microsoft Teams apps should always be single-tenant
43
44
  const MICROSOFT_TEAMS_APP_TYPE = "SingleTenant";
44
45
  // Maximum number of pages to fetch when paginating teams
@@ -1215,7 +1216,7 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1215
1216
  }
1216
1217
  // Bot Framework specific methods
1217
1218
  static async handleBotMessageActivity(data) {
1218
- var _a, _b, _c;
1219
+ var _a, _b, _c, _d;
1219
1220
  // Handle direct messages to bot or @mentions via Bot Framework
1220
1221
  const messageText = data.activity["text"] || "";
1221
1222
  const possibleActionValue = data.activity["value"] || {};
@@ -1228,9 +1229,23 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1228
1229
  logger.debug(`Conversation: ${JSON.stringify(conversation)}`);
1229
1230
  logger.debug(`Channel data: ${JSON.stringify(channelData)}`);
1230
1231
  logger.debug(`Entities: ${JSON.stringify(entities)}`);
1232
+ /*
1233
+ * Loop-guard: never process the bot's own messages. Teams generally does not
1234
+ * echo the bot to itself, but if the sender is the bot recipient (same id) or
1235
+ * is flagged with the "bot" role, ignore the activity to avoid a self-reply
1236
+ * loop when routing free-form text to the AI assistant.
1237
+ */
1238
+ const senderId = from["id"] || "";
1239
+ const botRecipientId = (_a = data.activity["recipient"]) === null || _a === void 0 ? void 0 : _a["id"];
1240
+ const senderRole = from["role"] || "";
1241
+ if (senderRole === "bot" ||
1242
+ (senderId && botRecipientId && senderId === botRecipientId)) {
1243
+ logger.debug("Message activity originates from the bot itself; ignoring to prevent a loop");
1244
+ return;
1245
+ }
1231
1246
  // If this is actually an Adaptive Card submit wrapped as a message, route to invoke handler
1232
1247
  if (possibleActionValue["action"] ||
1233
- ((_a = possibleActionValue["data"]) === null || _a === void 0 ? void 0 : _a["action"])) {
1248
+ ((_b = possibleActionValue["data"]) === null || _b === void 0 ? void 0 : _b["action"])) {
1234
1249
  logger.debug("Message activity contains action payload; routing to invoke handler");
1235
1250
  await this.handleBotInvokeActivity({
1236
1251
  activity: data.activity,
@@ -1239,7 +1254,7 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1239
1254
  return;
1240
1255
  }
1241
1256
  // Check if the bot was mentioned
1242
- const recipientId = (_b = data.activity["recipient"]) === null || _b === void 0 ? void 0 : _b["id"];
1257
+ const recipientId = (_c = data.activity["recipient"]) === null || _c === void 0 ? void 0 : _c["id"];
1243
1258
  const conversationType = conversation["conversationType"] || "";
1244
1259
  const isDirectMessage = conversationType === "personal";
1245
1260
  const isMentioned = entities.some((entity) => {
@@ -1253,7 +1268,7 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1253
1268
  return;
1254
1269
  }
1255
1270
  // Extract tenant ID to get project ID
1256
- const tenantId = (_c = channelData["tenant"]) === null || _c === void 0 ? void 0 : _c["id"];
1271
+ const tenantId = (_d = channelData["tenant"]) === null || _d === void 0 ? void 0 : _d["id"];
1257
1272
  if (!tenantId) {
1258
1273
  logger.error("Tenant ID not found in channelData");
1259
1274
  await data.turnContext.sendActivity("Sorry, I couldn't identify your organization. Please try again later.");
@@ -1287,13 +1302,40 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1287
1302
  .replace(/<at[^>]*>.*?<\/at>/g, "")
1288
1303
  .trim()
1289
1304
  .toLowerCase();
1305
+ /*
1306
+ * Preserve the original casing of the user's question. The AI assistant
1307
+ * should receive the free-form text exactly as the user typed it (case,
1308
+ * punctuation and spacing all matter), with only the bot @mention stripped.
1309
+ */
1310
+ const originalQuestionText = messageText
1311
+ .replace(/<at[^>]*>.*?<\/at>/g, "")
1312
+ .trim();
1290
1313
  let responseText = "";
1291
1314
  try {
1292
1315
  const isCreateIncidentCommand = cleanText === "create incident" ||
1293
1316
  cleanText.startsWith("create incident ");
1294
1317
  const isCreateMaintenanceCommand = cleanText === "create maintenance" ||
1295
1318
  cleanText.startsWith("create maintenance ");
1296
- if (cleanText.includes("help") || cleanText === "") {
1319
+ /*
1320
+ * Explicit commands are matched precisely so that natural-language
1321
+ * questions (which may incidentally contain words like "help" or
1322
+ * "alerts") fall through to the AI assistant instead of a canned command.
1323
+ */
1324
+ const isHelpCommand = cleanText === "help" || cleanText === "" || cleanText === "?";
1325
+ const isShowActiveIncidentsCommand = cleanText === "show active incidents" ||
1326
+ cleanText === "active incidents";
1327
+ const isShowScheduledMaintenanceCommand = cleanText === "show scheduled maintenance" ||
1328
+ cleanText === "scheduled maintenance";
1329
+ const isShowOngoingMaintenanceCommand = cleanText === "show ongoing maintenance" ||
1330
+ cleanText === "ongoing maintenance";
1331
+ const isShowActiveAlertsCommand = cleanText === "show active alerts" || cleanText === "active alerts";
1332
+ /*
1333
+ * "ask <question>" is an explicit prefix that always routes to the AI
1334
+ * assistant. When present, strip the prefix and use the remainder as the
1335
+ * question.
1336
+ */
1337
+ const isAskCommand = cleanText === "ask" || cleanText.startsWith("ask ");
1338
+ if (isHelpCommand) {
1297
1339
  responseText = this.getHelpMessage();
1298
1340
  }
1299
1341
  else if (isCreateIncidentCommand) {
@@ -1326,24 +1368,40 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1326
1368
  logger.debug("New scheduled maintenance card sent successfully");
1327
1369
  return;
1328
1370
  }
1329
- else if (cleanText.includes("show active incidents") ||
1330
- cleanText.includes("active incidents")) {
1371
+ else if (isShowActiveIncidentsCommand) {
1331
1372
  responseText = await this.getActiveIncidentsMessage(projectId);
1332
1373
  }
1333
- else if (cleanText.includes("show scheduled maintenance") ||
1334
- cleanText.includes("scheduled maintenance")) {
1374
+ else if (isShowScheduledMaintenanceCommand) {
1335
1375
  responseText = await this.getScheduledMaintenanceMessage(projectId);
1336
1376
  }
1337
- else if (cleanText.includes("show ongoing maintenance") ||
1338
- cleanText.includes("ongoing maintenance")) {
1377
+ else if (isShowOngoingMaintenanceCommand) {
1339
1378
  responseText = await this.getOngoingMaintenanceMessage(projectId);
1340
1379
  }
1341
- else if (cleanText.includes("show active alerts") ||
1342
- cleanText.includes("active alerts")) {
1380
+ else if (isShowActiveAlertsCommand) {
1343
1381
  responseText = await this.getActiveAlertsMessage(projectId);
1344
1382
  }
1345
1383
  else {
1346
- responseText = `I received your message: "${cleanText}". Type 'help' to see what I can do for you.`;
1384
+ /*
1385
+ * AI Ops: any message that is not one of the explicit commands above is
1386
+ * treated as a natural-language question for the observability
1387
+ * assistant. This also handles the explicit "ask <question>" prefix.
1388
+ */
1389
+ const question = isAskCommand
1390
+ ? originalQuestionText.replace(/^ask\s*/i, "").trim()
1391
+ : originalQuestionText;
1392
+ if (!question) {
1393
+ // Bare "ask" with no question - point the user at help.
1394
+ responseText = this.getHelpMessage();
1395
+ await data.turnContext.sendActivity(responseText);
1396
+ return;
1397
+ }
1398
+ await this.answerObservabilityQuestion({
1399
+ activity: data.activity,
1400
+ turnContext: data.turnContext,
1401
+ projectId: projectId,
1402
+ question: question,
1403
+ });
1404
+ return;
1347
1405
  }
1348
1406
  // Send response directly using TurnContext - this is the recommended Bot Framework pattern
1349
1407
  await data.turnContext.sendActivity(responseText);
@@ -1359,12 +1417,290 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1359
1417
  throw error;
1360
1418
  }
1361
1419
  }
1420
+ /*
1421
+ * AI Ops: strip a Teams message body down to plain text - remove <at> bot
1422
+ * mentions and any remaining HTML tags, collapse whitespace, and trim. Teams
1423
+ * channel/chat message bodies are typically HTML (body.contentType "html").
1424
+ */
1425
+ static toPlainTextFromTeamsMessageBody(rawContent) {
1426
+ return rawContent
1427
+ .replace(/<at[^>]*>.*?<\/at>/g, "")
1428
+ .replace(/<[^>]*>/g, "")
1429
+ .replace(/&nbsp;/g, " ")
1430
+ .replace(/\s+/g, " ")
1431
+ .trim();
1432
+ }
1433
+ /*
1434
+ * AI Ops: gather the prior turns of the current Teams conversation/thread and
1435
+ * map them to the assistant's history shape ({ role, content }, oldest-first,
1436
+ * excluding the current triggering message).
1437
+ *
1438
+ * Teams limitation: in channels a bot only receives messages that @mention it
1439
+ * (unless RSC / ChannelMessage.Read.Group is granted at install time), so
1440
+ * channel follow-ups generally require re-@mentioning the bot. 1:1 (personal)
1441
+ * chat follow-ups do not require a mention. If ids can't be parsed or the
1442
+ * Graph call fails, we degrade gracefully to no history - the caller wraps
1443
+ * this in a try/catch and never lets a history failure break the reply.
1444
+ */
1445
+ static async getConversationHistoryTurns(data) {
1446
+ var _a, _b, _c;
1447
+ const { activity, projectId } = data;
1448
+ const conversation = activity["conversation"] || {};
1449
+ const channelData = activity["channelData"] || {};
1450
+ const conversationType = conversation["conversationType"] || "";
1451
+ const conversationId = conversation["id"] || "";
1452
+ const currentMessageId = activity["id"] || "";
1453
+ /*
1454
+ * The bot's id - used to classify each message as "assistant" (from the
1455
+ * bot) vs "user". This is the same id the loop-guard compares against.
1456
+ */
1457
+ const botId = ((_a = activity["recipient"]) === null || _a === void 0 ? void 0 : _a["id"]) ||
1458
+ MicrosoftTeamsAppClientId ||
1459
+ "";
1460
+ if (!conversationId) {
1461
+ return [];
1462
+ }
1463
+ // Acquire a Graph app token using the same mechanism the rest of this file uses.
1464
+ const accessToken = await this.getValidAccessToken({
1465
+ authToken: "",
1466
+ projectId: projectId,
1467
+ });
1468
+ // Collect raw Graph message objects (unordered; we sort at the end).
1469
+ let rawMessages = [];
1470
+ if (conversationType === "personal") {
1471
+ /*
1472
+ * 1:1 chat: conversation.id is the chat id. Fetch recent chat messages.
1473
+ */
1474
+ const chatId = conversationId;
1475
+ const response = await API.get({
1476
+ url: URL.fromString(`https://graph.microsoft.com/v1.0/chats/${encodeURIComponent(chatId)}/messages?$top=20`),
1477
+ headers: {
1478
+ Authorization: `Bearer ${accessToken}`,
1479
+ "Content-Type": "application/json",
1480
+ },
1481
+ });
1482
+ if (response instanceof HTTPErrorResponse) {
1483
+ logger.debug("Failed to fetch 1:1 chat history for AI Ops context");
1484
+ logger.debug(response);
1485
+ return [];
1486
+ }
1487
+ rawMessages = response.data["value"] || [];
1488
+ }
1489
+ else {
1490
+ /*
1491
+ * Channel thread: conversation.id encodes the root message id as
1492
+ * "<channelId>;messageid=<rootId>". Team & channel ids come from
1493
+ * channelData. Fetch the root message plus its replies.
1494
+ */
1495
+ const teamId = (_b = channelData["team"]) === null || _b === void 0 ? void 0 : _b["id"];
1496
+ const channelId = (_c = channelData["channel"]) === null || _c === void 0 ? void 0 : _c["id"];
1497
+ const messageIdMatch = conversationId.match(/messageid=(\d+)/);
1498
+ const rootMessageId = messageIdMatch === null || messageIdMatch === void 0 ? void 0 : messageIdMatch[1];
1499
+ if (!teamId || !channelId || !rootMessageId) {
1500
+ logger.debug("Could not parse team/channel/root message ids for AI Ops channel history; proceeding without history");
1501
+ return [];
1502
+ }
1503
+ // Fetch replies in the thread.
1504
+ const repliesResponse = await API.get({
1505
+ url: URL.fromString(`https://graph.microsoft.com/v1.0/teams/${teamId}/channels/${channelId}/messages/${rootMessageId}/replies?$top=20`),
1506
+ headers: {
1507
+ Authorization: `Bearer ${accessToken}`,
1508
+ "Content-Type": "application/json",
1509
+ },
1510
+ });
1511
+ if (repliesResponse instanceof HTTPErrorResponse) {
1512
+ logger.debug("Failed to fetch channel thread replies for AI Ops context");
1513
+ logger.debug(repliesResponse);
1514
+ }
1515
+ else {
1516
+ rawMessages =
1517
+ repliesResponse.data["value"] || [];
1518
+ }
1519
+ // Also fetch the root message so the original question is part of context.
1520
+ const rootResponse = await API.get({
1521
+ url: URL.fromString(`https://graph.microsoft.com/v1.0/teams/${teamId}/channels/${channelId}/messages/${rootMessageId}`),
1522
+ headers: {
1523
+ Authorization: `Bearer ${accessToken}`,
1524
+ "Content-Type": "application/json",
1525
+ },
1526
+ });
1527
+ if (!(rootResponse instanceof HTTPErrorResponse) && rootResponse.data) {
1528
+ rawMessages.push(rootResponse.data);
1529
+ }
1530
+ }
1531
+ // Map each Graph message to a { role, content, createdAt, id } tuple.
1532
+ const mappedTurns = [];
1533
+ for (const message of rawMessages) {
1534
+ const messageId = message["id"] || "";
1535
+ // Exclude the current triggering message - that is the live question.
1536
+ if (messageId && currentMessageId && messageId === currentMessageId) {
1537
+ continue;
1538
+ }
1539
+ const body = message["body"] || {};
1540
+ const rawContent = body["content"] || "";
1541
+ const content = this.toPlainTextFromTeamsMessageBody(rawContent);
1542
+ if (!content) {
1543
+ continue;
1544
+ }
1545
+ // Skip the bot's transient "Looking into it…" acknowledgements.
1546
+ if (content === this.AI_OPS_ACK_TEXT) {
1547
+ continue;
1548
+ }
1549
+ /*
1550
+ * Classify sender. Graph marks bot/app messages via from.application; a
1551
+ * matching application/user id to the bot id also means it is the bot.
1552
+ */
1553
+ const fromObj = message["from"] || {};
1554
+ const fromApplication = fromObj["application"] || {};
1555
+ const fromUser = fromObj["user"] || {};
1556
+ const fromApplicationId = fromApplication["id"] || "";
1557
+ const fromUserId = fromUser["id"] || "";
1558
+ const isFromBot = Boolean(fromApplication["id"]) ||
1559
+ (botId !== "" && (fromApplicationId === botId || fromUserId === botId));
1560
+ const role = isFromBot ? "assistant" : "user";
1561
+ const createdAtRaw = message["createdDateTime"] || "";
1562
+ const createdAtMs = createdAtRaw
1563
+ ? new Date(createdAtRaw).getTime()
1564
+ : 0;
1565
+ mappedTurns.push({
1566
+ role: role,
1567
+ content: content,
1568
+ createdAtMs: createdAtMs,
1569
+ id: messageId,
1570
+ });
1571
+ }
1572
+ // Order oldest -> newest so the assistant reads the conversation in order.
1573
+ mappedTurns.sort((a, b) => {
1574
+ return a.createdAtMs - b.createdAtMs;
1575
+ });
1576
+ // Cap to the most recent turns.
1577
+ const cappedTurns = mappedTurns
1578
+ .slice(-this.AI_OPS_MAX_HISTORY_TURNS)
1579
+ .map((turn) => {
1580
+ return { role: turn.role, content: turn.content };
1581
+ });
1582
+ return cappedTurns;
1583
+ }
1584
+ /*
1585
+ * AI Ops: resolve the OneUptime user for the Teams sender, build their real
1586
+ * permission props, ask the observability assistant, and reply in the same
1587
+ * conversation with the markdown answer plus a compact "Sources" footer.
1588
+ */
1589
+ static async answerObservabilityQuestion(data) {
1590
+ const { activity, turnContext, projectId, question } = data;
1591
+ /*
1592
+ * Resolve the Teams user. Teams identifies the sender by their Azure AD
1593
+ * object id (aadObjectId), which is what WorkspaceUserAuthToken stores as
1594
+ * the workspaceUserId. This mirrors how handleBotInvokeActivity resolves
1595
+ * the acting user.
1596
+ */
1597
+ const fromObj = activity["from"] || {};
1598
+ const teamsUserId = fromObj["aadObjectId"] || undefined;
1599
+ if (!teamsUserId) {
1600
+ logger.error("AAD Object ID (teamsUserId) not found in message activity from object", {
1601
+ projectId: projectId.toString(),
1602
+ });
1603
+ await turnContext.sendActivity("Sorry, I couldn't identify you. Please try again later.");
1604
+ return;
1605
+ }
1606
+ // Resolve the OneUptime user linked to this Teams user.
1607
+ let oneUptimeUserId;
1608
+ try {
1609
+ oneUptimeUserId =
1610
+ await MicrosoftTeamsAuthAction.getOneUptimeUserIdFromTeamsUserId({
1611
+ teamsUserId: teamsUserId,
1612
+ projectId: projectId,
1613
+ });
1614
+ }
1615
+ catch (error) {
1616
+ logger.debug("No OneUptime user linked to Teams user; prompting to connect account", {
1617
+ projectId: projectId.toString(),
1618
+ workspaceUserId: teamsUserId,
1619
+ });
1620
+ logger.debug(error);
1621
+ await turnContext.sendActivity("I couldn't find your OneUptime account. Please connect your Microsoft Teams account in OneUptime User Settings before asking me questions.");
1622
+ return;
1623
+ }
1624
+ /*
1625
+ * Let the user know we're working on it. The assistant runs a bounded,
1626
+ * tool-grounded agent loop and can take several seconds, so send a quick
1627
+ * acknowledgement first.
1628
+ */
1629
+ try {
1630
+ await turnContext.sendActivity(this.AI_OPS_ACK_TEXT);
1631
+ }
1632
+ catch (ackError) {
1633
+ // A failed acknowledgement should not stop us from answering.
1634
+ logger.debug("Failed to send acknowledgement activity");
1635
+ logger.debug(ackError);
1636
+ }
1637
+ /*
1638
+ * Make the assistant context-aware: gather the prior turns of this
1639
+ * conversation/thread and pass them as history (oldest-first, excluding the
1640
+ * current question). Any failure here is non-fatal - we simply proceed
1641
+ * statelessly so a history problem never breaks the reply.
1642
+ */
1643
+ let history = [];
1644
+ try {
1645
+ history = await this.getConversationHistoryTurns({
1646
+ activity: activity,
1647
+ projectId: projectId,
1648
+ });
1649
+ logger.debug(`AI Ops gathered ${history.length} prior conversation turn(s) as history`, {
1650
+ projectId: projectId.toString(),
1651
+ });
1652
+ }
1653
+ catch (historyError) {
1654
+ logger.debug("Failed to gather AI Ops conversation history; proceeding statelessly");
1655
+ logger.debug(historyError);
1656
+ history = [];
1657
+ }
1658
+ try {
1659
+ // Build the user's real permission props - the assistant's tools run under these.
1660
+ const props = await AccessTokenService.getDatabaseCommonInteractionPropsByUserAndProject({
1661
+ userId: oneUptimeUserId,
1662
+ projectId: projectId,
1663
+ });
1664
+ /*
1665
+ * Loaded on demand via require(): importing the AI toolbox at module top
1666
+ * pulls the entire observability tool graph — and its database
1667
+ * infrastructure — into the core API module graph at import time, which
1668
+ * trips circular-dependency init-order crashes. Teams ChatOps is the only
1669
+ * caller, so it is resolved lazily here. A value-position dynamic
1670
+ * import() is avoided because it fails TS1323 under the consuming
1671
+ * projects' module configuration.
1672
+ */
1673
+ /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */
1674
+ const ObservabilityAssistant = require("../../AI/Chat/ObservabilityAssistant").default;
1675
+ /* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */
1676
+ const result = await ObservabilityAssistant.answerQuestion(Object.assign(Object.assign({ projectId: projectId, userId: oneUptimeUserId, props: props, question: question }, (history.length > 0 && { history: history })), { feature: "Microsoft Teams ChatOps" }));
1677
+ // Build a compact "Sources" footer from the server-minted citations.
1678
+ let replyText = result.contentInMarkdown;
1679
+ if (result.citations && result.citations.length > 0) {
1680
+ const sourceLines = result.citations.map((citation) => {
1681
+ return `• ${citation.label} (${citation.rowCount} rows)`;
1682
+ });
1683
+ replyText += `\n\n**Sources**\n${sourceLines.join("\n")}`;
1684
+ }
1685
+ await turnContext.sendActivity(replyText);
1686
+ logger.debug("AI Ops answer sent successfully using TurnContext", {
1687
+ projectId: projectId.toString(),
1688
+ });
1689
+ }
1690
+ catch (error) {
1691
+ logger.error("Error answering observability question via AI Ops: " + error, {
1692
+ projectId: projectId.toString(),
1693
+ });
1694
+ await turnContext.sendActivity("Sorry, I ran into a problem answering that question. Please try again later.");
1695
+ }
1696
+ }
1362
1697
  // Helper methods for bot commands
1363
1698
  static getHelpMessage() {
1364
1699
  return `Hello! I'm the OneUptime bot. I can help you with the following commands:
1365
1700
 
1366
1701
  **Available Commands:**
1367
1702
  - **help** - Show this help message
1703
+ - **ask <question>** - Ask OneUptime AI about your logs, traces, metrics, incidents and monitors
1368
1704
  - **create incident** - Create a new incident
1369
1705
  - **create maintenance** - Create a new scheduled maintenance event
1370
1706
  - **show active incidents** - Display all currently active incidents
@@ -1372,7 +1708,7 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
1372
1708
  - **show ongoing maintenance** - Display currently ongoing maintenance events
1373
1709
  - **show active alerts** - Display all active alerts
1374
1710
 
1375
- Just type any of these commands to get the information you need!`;
1711
+ You can also just ask me a question in plain language - for example, "which monitors are down right now?" - and I'll look into your observability data for you.`;
1376
1712
  }
1377
1713
  static async getActiveIncidentsMessage(projectId) {
1378
1714
  var _a, _b;
@@ -2045,6 +2381,10 @@ All monitoring checks are passing normally.`;
2045
2381
  title: "help",
2046
2382
  value: "Show quick help and useful links",
2047
2383
  },
2384
+ {
2385
+ title: "ask",
2386
+ value: "Ask OneUptime AI about your logs, traces, metrics, incidents and monitors",
2387
+ },
2048
2388
  {
2049
2389
  title: "create incident",
2050
2390
  value: "Create a new incident without leaving Teams",
@@ -2412,6 +2752,17 @@ All monitoring checks are passing normally.`;
2412
2752
  }
2413
2753
  MicrosoftTeamsUtil.cachedAdapter = null;
2414
2754
  MicrosoftTeamsUtil.WELCOME_CARD_STATE_KEY = "oneuptime.microsoftTeams.welcomeCardSent";
2755
+ /*
2756
+ * AI Ops: transient acknowledgement text the bot posts before answering. We
2757
+ * must skip these when reconstructing conversation history so the assistant
2758
+ * never treats its own "please wait" filler as a real prior turn.
2759
+ */
2760
+ MicrosoftTeamsUtil.AI_OPS_ACK_TEXT = "Looking into it…";
2761
+ /*
2762
+ * AI Ops: cap on how many prior turns we feed the assistant as history. The
2763
+ * engine also clamps history internally, but we keep the payload small.
2764
+ */
2765
+ MicrosoftTeamsUtil.AI_OPS_MAX_HISTORY_TURNS = 12;
2415
2766
  export default MicrosoftTeamsUtil;
2416
2767
  __decorate([
2417
2768
  CaptureSpan(),
@@ -2617,6 +2968,18 @@ __decorate([
2617
2968
  __metadata("design:paramtypes", [Object]),
2618
2969
  __metadata("design:returntype", Promise)
2619
2970
  ], MicrosoftTeamsUtil, "handleBotMessageActivity", null);
2971
+ __decorate([
2972
+ CaptureSpan(),
2973
+ __metadata("design:type", Function),
2974
+ __metadata("design:paramtypes", [Object]),
2975
+ __metadata("design:returntype", Promise)
2976
+ ], MicrosoftTeamsUtil, "getConversationHistoryTurns", null);
2977
+ __decorate([
2978
+ CaptureSpan(),
2979
+ __metadata("design:type", Function),
2980
+ __metadata("design:paramtypes", [Object]),
2981
+ __metadata("design:returntype", Promise)
2982
+ ], MicrosoftTeamsUtil, "answerObservabilityQuestion", null);
2620
2983
  __decorate([
2621
2984
  CaptureSpan(),
2622
2985
  __metadata("design:type", Function),