Files
horus-3d/src/features/agents/operations/deleteAgentOperation.ts
T
Luke The Dev 4fa4f13558 First Release of Claw3D (#11)
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
2026-03-19 23:14:04 -05:00

119 lines
3.8 KiB
TypeScript

import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import { fetchJson as defaultFetchJson } from "@/lib/http";
import {
removeCronJobsForAgentWithBackup,
restoreCronJobs,
type CronJobRestoreInput,
} from "@/lib/cron/types";
import { deleteGatewayAgent } from "@/lib/gateway/agentConfig";
type FetchJson = typeof defaultFetchJson;
export type GatewayAgentStateMove = { from: string; to: string };
export type TrashAgentStateResult = {
trashDir: string;
moved: GatewayAgentStateMove[];
};
export type RestoreAgentStateResult = {
restored: GatewayAgentStateMove[];
};
type DeleteAgentTransactionDeps = {
trashAgentState: (agentId: string) => Promise<TrashAgentStateResult>;
restoreAgentState: (agentId: string, trashDir: string) => Promise<RestoreAgentStateResult>;
removeCronJobsForAgentWithBackup: (agentId: string) => Promise<CronJobRestoreInput[]>;
restoreCronJobs: (jobs: CronJobRestoreInput[]) => Promise<void>;
deleteGatewayAgent: (agentId: string) => Promise<void>;
logError?: (message: string, error: unknown) => void;
};
export type DeleteAgentTransactionResult = {
trashed: TrashAgentStateResult;
restored: RestoreAgentStateResult | null;
};
const runDeleteFlow = async (
deps: DeleteAgentTransactionDeps,
agentId: string
): Promise<DeleteAgentTransactionResult> => {
const trimmedAgentId = agentId.trim();
if (!trimmedAgentId) {
throw new Error("Agent id is required.");
}
const trashed = await deps.trashAgentState(trimmedAgentId);
let removedCronJobs: CronJobRestoreInput[] = [];
try {
removedCronJobs = await deps.removeCronJobsForAgentWithBackup(trimmedAgentId);
await deps.deleteGatewayAgent(trimmedAgentId);
return { trashed, restored: null };
} catch (err) {
if (removedCronJobs.length > 0) {
try {
await deps.restoreCronJobs(removedCronJobs);
} catch (restoreCronErr) {
deps.logError?.("Failed to restore removed cron jobs.", restoreCronErr);
}
}
if (trashed.moved.length > 0) {
try {
await deps.restoreAgentState(trimmedAgentId, trashed.trashDir);
} catch (restoreErr) {
deps.logError?.("Failed to restore trashed agent state.", restoreErr);
}
}
throw err;
}
};
export const deleteAgentViaStudio = async (params: {
client: GatewayClient;
agentId: string;
fetchJson?: FetchJson;
logError?: (message: string, error: unknown) => void;
}): Promise<DeleteAgentTransactionResult> => {
const fetchJson = params.fetchJson ?? defaultFetchJson;
const logError = params.logError ?? ((message, error) => console.error(message, error));
return runDeleteFlow(
{
trashAgentState: async (agentId) => {
const { result } = await fetchJson<{ result: TrashAgentStateResult }>(
"/api/gateway/agent-state",
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ agentId }),
}
);
return result;
},
restoreAgentState: async (agentId, trashDir) => {
const { result } = await fetchJson<{ result: RestoreAgentStateResult }>(
"/api/gateway/agent-state",
{
method: "PUT",
headers: { "content-type": "application/json" },
body: JSON.stringify({ agentId, trashDir }),
}
);
return result;
},
removeCronJobsForAgentWithBackup: async (agentId) => {
return await removeCronJobsForAgentWithBackup(params.client, agentId);
},
restoreCronJobs: async (jobs) => {
await restoreCronJobs(params.client, jobs);
},
deleteGatewayAgent: async (agentId) => {
await deleteGatewayAgent({ client: params.client, agentId });
},
logError,
},
params.agentId
);
};