mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
172 lines
5.3 KiB
TypeScript
172 lines
5.3 KiB
TypeScript
import DatabaseService from "./DatabaseService";
|
|
import Model from "../../Models/DatabaseModels/TelemetryException";
|
|
import AIAgentTask from "../../Models/DatabaseModels/AIAgentTask";
|
|
import AIAgentTaskTelemetryException from "../../Models/DatabaseModels/AIAgentTaskTelemetryException";
|
|
import ObjectID from "../../Types/ObjectID";
|
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
import AIAgentTaskType from "../../Types/AI/AIAgentTaskType";
|
|
import AIAgentTaskStatus from "../../Types/AI/AIAgentTaskStatus";
|
|
import { FixExceptionTaskMetadata } from "../../Types/AI/AIAgentTaskMetadata";
|
|
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
import AIAgentTaskService from "./AIAgentTaskService";
|
|
import AIAgentTaskTelemetryExceptionService from "./AIAgentTaskTelemetryExceptionService";
|
|
import QueryHelper from "../Types/Database/QueryHelper";
|
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
|
export interface CreateAIAgentTaskForExceptionParams {
|
|
telemetryExceptionId: ObjectID;
|
|
props: DatabaseCommonInteractionProps;
|
|
}
|
|
|
|
export class Service extends DatabaseService<Model> {
|
|
public constructor() {
|
|
super(Model);
|
|
}
|
|
|
|
@CaptureSpan()
|
|
public async createAIAgentTaskForException(
|
|
params: CreateAIAgentTaskForExceptionParams,
|
|
): Promise<AIAgentTask> {
|
|
const { telemetryExceptionId, props } = params;
|
|
|
|
// Get the telemetry exception
|
|
const telemetryException: Model | null = await this.findOneById({
|
|
id: telemetryExceptionId,
|
|
select: {
|
|
_id: true,
|
|
projectId: true,
|
|
message: true,
|
|
stackTrace: true,
|
|
serviceId: true,
|
|
exceptionType: true,
|
|
},
|
|
props,
|
|
});
|
|
|
|
if (!telemetryException || !telemetryException.projectId) {
|
|
throw new BadDataException("Telemetry Exception not found");
|
|
}
|
|
|
|
// Check if an active AI agent task already exists for this exception
|
|
await this.validateNoActiveTaskExists(telemetryExceptionId);
|
|
|
|
// Create the AI Agent Task
|
|
const createdTask: AIAgentTask = await this.createFixExceptionTask({
|
|
telemetryException,
|
|
telemetryExceptionId,
|
|
props,
|
|
});
|
|
|
|
// Link the task to the telemetry exception
|
|
await AIAgentTaskTelemetryExceptionService.linkTaskToTelemetryException({
|
|
projectId: telemetryException.projectId,
|
|
aiAgentTaskId: createdTask.id!,
|
|
telemetryExceptionId,
|
|
props,
|
|
});
|
|
|
|
return createdTask;
|
|
}
|
|
|
|
@CaptureSpan()
|
|
private async validateNoActiveTaskExists(
|
|
telemetryExceptionId: ObjectID,
|
|
): Promise<void> {
|
|
const existingTaskLink: AIAgentTaskTelemetryException | null =
|
|
await AIAgentTaskTelemetryExceptionService.findOneBy({
|
|
query: {
|
|
telemetryExceptionId: telemetryExceptionId,
|
|
aiAgentTask: {
|
|
status: QueryHelper.notIn([
|
|
AIAgentTaskStatus.Completed,
|
|
AIAgentTaskStatus.Error,
|
|
]),
|
|
},
|
|
},
|
|
select: {
|
|
_id: true,
|
|
aiAgentTaskId: true,
|
|
},
|
|
props: {
|
|
isRoot: true,
|
|
},
|
|
});
|
|
|
|
if (existingTaskLink) {
|
|
throw new BadDataException(
|
|
"An AI agent task is already in progress for this exception. Please wait for it to complete before creating a new one.",
|
|
);
|
|
}
|
|
}
|
|
|
|
@CaptureSpan()
|
|
private async createFixExceptionTask(params: {
|
|
telemetryException: Model;
|
|
telemetryExceptionId: ObjectID;
|
|
props: DatabaseCommonInteractionProps;
|
|
}): Promise<AIAgentTask> {
|
|
const { telemetryException, telemetryExceptionId, props } = params;
|
|
|
|
const aiAgentTask: AIAgentTask = new AIAgentTask();
|
|
aiAgentTask.projectId = telemetryException.projectId!;
|
|
aiAgentTask.taskType = AIAgentTaskType.FixException;
|
|
aiAgentTask.status = AIAgentTaskStatus.Scheduled;
|
|
|
|
// Set name and description based on exception details
|
|
const exceptionType: string =
|
|
telemetryException.exceptionType || "Exception";
|
|
const exceptionMessage: string =
|
|
telemetryException.message || "No message available";
|
|
|
|
aiAgentTask.name = `Fix ${exceptionType}: ${exceptionMessage}`;
|
|
aiAgentTask.description = `AI Agent task to fix the exception: ${exceptionMessage}`;
|
|
|
|
// Build metadata
|
|
aiAgentTask.metadata = this.buildFixExceptionMetadata({
|
|
telemetryException,
|
|
telemetryExceptionId,
|
|
});
|
|
|
|
const createdTask: AIAgentTask = await AIAgentTaskService.create({
|
|
data: aiAgentTask,
|
|
props: {
|
|
...props,
|
|
},
|
|
});
|
|
|
|
if (!createdTask.id) {
|
|
throw new BadDataException("Failed to create AI Agent Task");
|
|
}
|
|
|
|
return createdTask;
|
|
}
|
|
|
|
private buildFixExceptionMetadata(params: {
|
|
telemetryException: Model;
|
|
telemetryExceptionId: ObjectID;
|
|
}): FixExceptionTaskMetadata {
|
|
const { telemetryException, telemetryExceptionId } = params;
|
|
|
|
const metadata: FixExceptionTaskMetadata = {
|
|
taskType: AIAgentTaskType.FixException,
|
|
exceptionId: telemetryExceptionId.toString(),
|
|
};
|
|
|
|
if (telemetryException.stackTrace) {
|
|
metadata.stackTrace = telemetryException.stackTrace;
|
|
}
|
|
|
|
if (telemetryException.message) {
|
|
metadata.errorMessage = telemetryException.message;
|
|
}
|
|
|
|
if (telemetryException.serviceId) {
|
|
metadata.serviceId = telemetryException.serviceId.toString();
|
|
}
|
|
|
|
return metadata;
|
|
}
|
|
}
|
|
|
|
export default new Service();
|