ai-chatbot/components/canvas/chat-panel/canvas-agent-targets.ts

60 lines
1.6 KiB
TypeScript

import type { CanvasNode } from "@/types/canvas";
export type PendingCanvasAgentTarget = {
nodeId?: string | null;
requestedAt?: number | null;
};
const DEFAULT_PENDING_TARGET_MAX_AGE_MS = 10 * 60 * 1000;
function normalizeNodeId(value: unknown) {
return typeof value === "string" ? value.trim() : "";
}
export function resolvePendingCanvasAgentTargetNode(params: {
nodes: CanvasNode[];
pendingTarget?: PendingCanvasAgentTarget | null;
now?: number;
maxAgeMs?: number;
isEligibleNode?: (node: CanvasNode) => boolean;
}) {
const nodeId = normalizeNodeId(params.pendingTarget?.nodeId);
if (!nodeId) return null;
const requestedAt = Number(params.pendingTarget?.requestedAt || 0);
const now = Number(params.now ?? Date.now());
const maxAgeMs = Math.max(
0,
Number(params.maxAgeMs ?? DEFAULT_PENDING_TARGET_MAX_AGE_MS)
);
if (
Number.isFinite(requestedAt) &&
requestedAt > 0 &&
Number.isFinite(now) &&
now - requestedAt > maxAgeMs
) {
return null;
}
const node = params.nodes.find((item) => item.id === nodeId) || null;
if (!node) return null;
if (params.isEligibleNode && !params.isEligibleNode(node)) return null;
return node;
}
export function mergePendingCanvasAgentTargetNodeIds(params: {
selectedNodeIds: string[];
pendingTargetNodeId?: string | null;
maxItems?: number;
}) {
const maxItems = Math.max(1, Number(params.maxItems || 20));
return Array.from(
new Set(
[
...params.selectedNodeIds,
normalizeNodeId(params.pendingTargetNodeId),
].filter(Boolean)
)
).slice(0, maxItems);
}