feat: Enhance AIAgentTask migration, metadata, and status handling

This commit is contained in:
Nawaz Dhandala
2025-12-25 18:59:46 +00:00
parent 90ddd29e0e
commit 7a2a79ceba
12 changed files with 109 additions and 68 deletions

View File

@@ -1,30 +1,63 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class MigrationName1766688107858 implements MigrationInterface {
public name = 'MigrationName1766688107858'
public name = "MigrationName1766688107858";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "AIAgentTask" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "aiAgentId" uuid, "taskType" character varying(100) NOT NULL, "status" character varying(100) NOT NULL DEFAULT 'Scheduled', "statusMessage" character varying, "metadata" jsonb, "startedAt" TIMESTAMP WITH TIME ZONE, "completedAt" TIMESTAMP WITH TIME ZONE, "deletedByUserId" uuid, "createdByUserId" uuid, CONSTRAINT "PK_eb04a1e2a82c4ce10c5f7c71199" PRIMARY KEY ("_id"))`);
await queryRunner.query(`CREATE INDEX "IDX_8d59c1b022154b111bd972b6df" ON "AIAgentTask" ("projectId") `);
await queryRunner.query(`CREATE INDEX "IDX_660485cda8f31485ddcc34521c" ON "AIAgentTask" ("aiAgentId") `);
await queryRunner.query(`CREATE INDEX "IDX_abce8c37353599dcd416f5c8b3" ON "AIAgentTask" ("taskType") `);
await queryRunner.query(`CREATE INDEX "IDX_a3e7acb3ba2d54e97989b809f6" ON "AIAgentTask" ("status") `);
await queryRunner.query(`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_8d59c1b022154b111bd972b6df5" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_660485cda8f31485ddcc34521cc" FOREIGN KEY ("aiAgentId") REFERENCES "AIAgent"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_ca3dba8a1e85ba0dd227636886a" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_e26c0359ca57facf6af5714c12c" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_e26c0359ca57facf6af5714c12c"`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_ca3dba8a1e85ba0dd227636886a"`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_660485cda8f31485ddcc34521cc"`);
await queryRunner.query(`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_8d59c1b022154b111bd972b6df5"`);
await queryRunner.query(`DROP INDEX "public"."IDX_a3e7acb3ba2d54e97989b809f6"`);
await queryRunner.query(`DROP INDEX "public"."IDX_abce8c37353599dcd416f5c8b3"`);
await queryRunner.query(`DROP INDEX "public"."IDX_660485cda8f31485ddcc34521c"`);
await queryRunner.query(`DROP INDEX "public"."IDX_8d59c1b022154b111bd972b6df"`);
await queryRunner.query(`DROP TABLE "AIAgentTask"`);
}
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "AIAgentTask" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "aiAgentId" uuid, "taskType" character varying(100) NOT NULL, "status" character varying(100) NOT NULL DEFAULT 'Scheduled', "statusMessage" character varying, "metadata" jsonb, "startedAt" TIMESTAMP WITH TIME ZONE, "completedAt" TIMESTAMP WITH TIME ZONE, "deletedByUserId" uuid, "createdByUserId" uuid, CONSTRAINT "PK_eb04a1e2a82c4ce10c5f7c71199" PRIMARY KEY ("_id"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_8d59c1b022154b111bd972b6df" ON "AIAgentTask" ("projectId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_660485cda8f31485ddcc34521c" ON "AIAgentTask" ("aiAgentId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_abce8c37353599dcd416f5c8b3" ON "AIAgentTask" ("taskType") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_a3e7acb3ba2d54e97989b809f6" ON "AIAgentTask" ("status") `,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_8d59c1b022154b111bd972b6df5" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_660485cda8f31485ddcc34521cc" FOREIGN KEY ("aiAgentId") REFERENCES "AIAgent"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_ca3dba8a1e85ba0dd227636886a" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" ADD CONSTRAINT "FK_e26c0359ca57facf6af5714c12c" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_e26c0359ca57facf6af5714c12c"`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_ca3dba8a1e85ba0dd227636886a"`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_660485cda8f31485ddcc34521cc"`,
);
await queryRunner.query(
`ALTER TABLE "AIAgentTask" DROP CONSTRAINT "FK_8d59c1b022154b111bd972b6df5"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_a3e7acb3ba2d54e97989b809f6"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_abce8c37353599dcd416f5c8b3"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_660485cda8f31485ddcc34521c"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_8d59c1b022154b111bd972b6df"`,
);
await queryRunner.query(`DROP TABLE "AIAgentTask"`);
}
}

View File

@@ -415,5 +415,5 @@ export default [
MigrationName1766590916627,
MigrationName1766600860972,
MigrationName1766606720183,
MigrationName1766688107858
MigrationName1766688107858,
];

View File

@@ -14,11 +14,8 @@ export interface FixExceptionTaskMetadata extends AIAgentTaskMetadataBase {
errorMessage?: string;
}
// Union type for all task metadata types
export type AIAgentTaskMetadata =
| FixExceptionTaskMetadata; // More tasks can be added here in the future
export type AIAgentTaskMetadata = FixExceptionTaskMetadata; // More tasks can be added here in the future
// Type guard functions
export function isFixExceptionMetadata(

View File

@@ -19,7 +19,8 @@ export class AIAgentTaskStatusHelper {
{
status: AIAgentTaskStatus.Scheduled,
title: "Scheduled",
description: "Task is scheduled and waiting to be picked up by an agent.",
description:
"Task is scheduled and waiting to be picked up by an agent.",
},
{
status: AIAgentTaskStatus.InProgress,
@@ -41,17 +42,17 @@ export class AIAgentTaskStatusHelper {
public static getDescription(status: AIAgentTaskStatus): string {
const props: AIAgentTaskStatusProps | undefined =
this.getAllStatusProps().find(
(p: AIAgentTaskStatusProps) => p.status === status,
);
this.getAllStatusProps().find((p: AIAgentTaskStatusProps) => {
return p.status === status;
});
return props?.description || "";
}
public static getTitle(status: AIAgentTaskStatus): string {
const props: AIAgentTaskStatusProps | undefined =
this.getAllStatusProps().find(
(p: AIAgentTaskStatusProps) => p.status === status,
);
this.getAllStatusProps().find((p: AIAgentTaskStatusProps) => {
return p.status === status;
});
return props?.title || "";
}

View File

@@ -1,5 +1,5 @@
enum AIAgentTaskType {
FixException = "FixException"
FixException = "FixException",
}
export default AIAgentTaskType;
@@ -18,23 +18,23 @@ export class AIAgentTaskTypeHelper {
title: "Fix Exception",
description:
"Analyze and fix an exception that occurred in your application.",
}
},
];
}
public static getDescription(taskType: AIAgentTaskType): string {
const props: AIAgentTaskTypeProps | undefined =
this.getAllTaskTypeProps().find(
(p: AIAgentTaskTypeProps) => p.taskType === taskType,
);
this.getAllTaskTypeProps().find((p: AIAgentTaskTypeProps) => {
return p.taskType === taskType;
});
return props?.description || "";
}
public static getTitle(taskType: AIAgentTaskType): string {
const props: AIAgentTaskTypeProps | undefined =
this.getAllTaskTypeProps().find(
(p: AIAgentTaskTypeProps) => p.taskType === taskType,
);
this.getAllTaskTypeProps().find((p: AIAgentTaskTypeProps) => {
return p.taskType === taskType;
});
return props?.title || "";
}
}

View File

@@ -85,7 +85,8 @@ const DashboardNavbar: FunctionComponent<ComponentProps> = (
const moreMenuItems: MoreMenuItem[] = [
{
title: "AI Agent",
description: "Manage tasks assigned to AI agents for automated operations.",
description:
"Manage tasks assigned to AI agents for automated operations.",
route: RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASKS] as Route,
),

View File

@@ -42,7 +42,8 @@ const AIAgentTasksPage: FunctionComponent<
fieldType: FormFieldSchemaType.Dropdown,
required: true,
placeholder: "Select Task Type",
dropdownOptions: DropdownUtil.getDropdownOptionsFromEnum(AIAgentTaskType),
dropdownOptions:
DropdownUtil.getDropdownOptionsFromEnum(AIAgentTaskType),
},
{
field: {
@@ -149,9 +150,12 @@ const AIAgentTasksPage: FunctionComponent<
]}
onViewPage={(item: AIAgentTask): Promise<Route> => {
return Promise.resolve(
RouteUtil.populateRouteParams(RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route, {
modelId: item._id,
}),
RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route,
{
modelId: item._id,
},
),
);
}}
/>

View File

@@ -104,9 +104,12 @@ const CompletedTasksPage: FunctionComponent<
]}
onViewPage={(item: AIAgentTask): Promise<Route> => {
return Promise.resolve(
RouteUtil.populateRouteParams(RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route, {
modelId: item._id,
}),
RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route,
{
modelId: item._id,
},
),
);
}}
/>

View File

@@ -29,8 +29,7 @@ const InProgressTasksPage: FunctionComponent<
}}
cardProps={{
title: "In Progress Tasks",
description:
"Tasks that are currently being processed by an AI agent.",
description: "Tasks that are currently being processed by an AI agent.",
}}
showViewIdButton={true}
filters={[
@@ -104,9 +103,12 @@ const InProgressTasksPage: FunctionComponent<
]}
onViewPage={(item: AIAgentTask): Promise<Route> => {
return Promise.resolve(
RouteUtil.populateRouteParams(RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route, {
modelId: item._id,
}),
RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route,
{
modelId: item._id,
},
),
);
}}
/>

View File

@@ -104,9 +104,12 @@ const ScheduledTasksPage: FunctionComponent<
]}
onViewPage={(item: AIAgentTask): Promise<Route> => {
return Promise.resolve(
RouteUtil.populateRouteParams(RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route, {
modelId: item._id,
}),
RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASK_VIEW] as Route,
{
modelId: item._id,
},
),
);
}}
/>

View File

@@ -18,9 +18,7 @@ const DeletePage: FunctionComponent<PageComponentProps> = (): ReactElement => {
modelId={modelId}
onDeleteSuccess={() => {
Navigation.navigate(
RouteUtil.populateRouteParams(
RouteMap[PageMap.AI_AGENT_TASKS]!,
),
RouteUtil.populateRouteParams(RouteMap[PageMap.AI_AGENT_TASKS]!),
);
}}
/>

View File

@@ -3,10 +3,7 @@ import ComponentProps from "../Pages/PageComponentProps";
import AIAgentTasksLayout from "../Pages/AIAgentTasks/Layout";
import AIAgentTaskViewLayout from "../Pages/AIAgentTasks/View/Layout";
import PageMap from "../Utils/PageMap";
import RouteMap, {
RouteUtil,
AIAgentTasksRoutePath,
} from "../Utils/RouteMap";
import RouteMap, { RouteUtil, AIAgentTasksRoutePath } from "../Utils/RouteMap";
import Route from "Common/Types/API/Route";
import React, {
FunctionComponent,
@@ -97,7 +94,9 @@ const AIAgentTasksRoutes: FunctionComponent<ComponentProps> = (
<Suspense fallback={Loader}>
<AIAgentTasksInProgress
{...props}
pageRoute={RouteMap[PageMap.AI_AGENT_TASKS_IN_PROGRESS] as Route}
pageRoute={
RouteMap[PageMap.AI_AGENT_TASKS_IN_PROGRESS] as Route
}
/>
</Suspense>
}