119 lines
3.9 KiB
TypeScript
119 lines
3.9 KiB
TypeScript
import type { CanvasOperationPlan } from "@/types/canvas/agent-protocol";
|
|
|
|
export type CanvasAgentOperationAuditCanvasData = {
|
|
metadata?: unknown;
|
|
[key: string]: unknown;
|
|
};
|
|
|
|
function normalizeCanvasMetadata(value: unknown) {
|
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
? { ...(value as Record<string, unknown>) }
|
|
: {};
|
|
}
|
|
|
|
export function getCanvasAgentOperationAudit(
|
|
canvasData: CanvasAgentOperationAuditCanvasData
|
|
) {
|
|
const metadata = normalizeCanvasMetadata(canvasData.metadata);
|
|
const audit = Array.isArray(metadata.canvasAgentOperationAudit)
|
|
? metadata.canvasAgentOperationAudit
|
|
: [];
|
|
return audit.filter((item) => item && typeof item === "object").slice(-30);
|
|
}
|
|
|
|
export function findCanvasAgentOperationAudit(
|
|
canvasData: CanvasAgentOperationAuditCanvasData,
|
|
operationId: string
|
|
) {
|
|
return getCanvasAgentOperationAudit(canvasData).find(
|
|
(item) =>
|
|
String((item as Record<string, unknown>).operationId || "").trim() ===
|
|
operationId
|
|
) as Record<string, unknown> | undefined;
|
|
}
|
|
|
|
export function normalizeCanvasAgentAuditStringList(value: unknown) {
|
|
return Array.isArray(value)
|
|
? value.map((item) => String(item || "").trim()).filter(Boolean)
|
|
: [];
|
|
}
|
|
|
|
export function buildIdempotentCanvasAgentAuditResult(params: {
|
|
canvasData: CanvasAgentOperationAuditCanvasData;
|
|
audit: Record<string, unknown>;
|
|
}) {
|
|
return {
|
|
canvasData: params.canvasData,
|
|
createdNodeIds: normalizeCanvasAgentAuditStringList(params.audit.createdNodeIds),
|
|
createdNodeIdsByMediaItemId:
|
|
params.audit.createdNodeIdsByMediaItemId &&
|
|
typeof params.audit.createdNodeIdsByMediaItemId === "object" &&
|
|
!Array.isArray(params.audit.createdNodeIdsByMediaItemId)
|
|
? Object.fromEntries(
|
|
Object.entries(
|
|
params.audit.createdNodeIdsByMediaItemId as Record<string, unknown>
|
|
)
|
|
.map(([mediaItemId, nodeId]) => [
|
|
String(mediaItemId || "").trim(),
|
|
String(nodeId || "").trim(),
|
|
])
|
|
.filter(([mediaItemId, nodeId]) => mediaItemId && nodeId)
|
|
)
|
|
: {},
|
|
updatedNodeIds: normalizeCanvasAgentAuditStringList(params.audit.updatedNodeIds),
|
|
createdEdgeIds: normalizeCanvasAgentAuditStringList(params.audit.createdEdgeIds),
|
|
};
|
|
}
|
|
|
|
export function appendCanvasAgentOperationAudit<T extends CanvasAgentOperationAuditCanvasData>(
|
|
params: {
|
|
canvasData: T;
|
|
auditEntry: Record<string, unknown>;
|
|
}
|
|
): T {
|
|
const metadata = normalizeCanvasMetadata(params.canvasData.metadata);
|
|
const audit = getCanvasAgentOperationAudit(params.canvasData);
|
|
return {
|
|
...params.canvasData,
|
|
metadata: {
|
|
...metadata,
|
|
canvasAgentOperationAudit: [...audit, params.auditEntry].slice(-30),
|
|
},
|
|
};
|
|
}
|
|
|
|
export function appendCanvasAgentOperationAuditIfMissing<
|
|
T extends CanvasAgentOperationAuditCanvasData,
|
|
>(params: {
|
|
canvasData: T;
|
|
plan: CanvasOperationPlan;
|
|
result: {
|
|
createdNodeIds: string[];
|
|
createdNodeIdsByMediaItemId: Record<string, string>;
|
|
updatedNodeIds: string[];
|
|
createdEdgeIds: string[];
|
|
};
|
|
}) {
|
|
if (findCanvasAgentOperationAudit(params.canvasData, params.plan.operationId)) {
|
|
return params.canvasData;
|
|
}
|
|
|
|
return appendCanvasAgentOperationAudit({
|
|
canvasData: params.canvasData,
|
|
auditEntry: {
|
|
operationId: params.plan.operationId,
|
|
operation: params.plan.operation,
|
|
createdNodeIds: params.result.createdNodeIds,
|
|
createdNodeIdsByMediaItemId: params.result.createdNodeIdsByMediaItemId,
|
|
updatedNodeIds: params.result.updatedNodeIds,
|
|
createdEdgeIds: params.result.createdEdgeIds,
|
|
sourceNodeIds: params.plan.sourceNodeIds || [],
|
|
targetNodeIds: params.plan.targetNodeIds || [],
|
|
targetSlotId: params.plan.targetSlotId,
|
|
anchorNodeId: params.plan.anchorNodeId,
|
|
appliedAt: new Date().toISOString(),
|
|
metadata: params.plan.metadata || {},
|
|
},
|
|
});
|
|
}
|