diff --git a/components/canvas/nodes/agent-node.tsx b/components/canvas/nodes/agent-node.tsx index 8d283ad..3305d91 100644 --- a/components/canvas/nodes/agent-node.tsx +++ b/components/canvas/nodes/agent-node.tsx @@ -5,6 +5,8 @@ import { Bot } from "lucide-react"; import { Handle, Position, type Node, type NodeProps } from "@xyflow/react"; import { useAction } from "convex/react"; import type { FunctionReference } from "convex/server"; +import { useTranslations } from "next-intl"; +import { useLocale } from "next-intl"; import { api } from "@/convex/_generated/api"; import type { Id } from "@/convex/_generated/dataModel"; @@ -37,6 +39,13 @@ type AgentNodeData = { templateId?: string; canvasId?: string; modelId?: string; + briefConstraints?: { + briefing?: string; + audience?: string; + tone?: string; + targetChannels?: string[]; + hardConstraints?: string[]; + }; executionSteps?: Array<{ stepIndex?: number; stepTotal?: number }>; executionStepIndex?: number; executionStepTotal?: number; @@ -48,6 +57,14 @@ type AgentNodeData = { _statusMessage?: string; }; +type AgentBriefConstraints = { + briefing: string; + audience: string; + tone: string; + targetChannels: string[]; + hardConstraints: string[]; +}; + type AgentNodeType = Node; const DEFAULT_AGENT_TEMPLATE_ID = "campaign-distributor"; @@ -114,6 +131,46 @@ function areAnswerMapsEqual( return true; } +function normalizeDelimitedList(value: string, allowNewLines = false): string[] { + const separator = allowNewLines ? /[\n,]/ : /,/; + return value + .split(separator) + .map((item) => item.trim()) + .filter((item) => item.length > 0); +} + +function normalizeBriefConstraints(raw: AgentNodeData["briefConstraints"]): AgentBriefConstraints { + return { + briefing: typeof raw?.briefing === "string" ? raw.briefing : "", + audience: typeof raw?.audience === "string" ? raw.audience : "", + tone: typeof raw?.tone === "string" ? raw.tone : "", + targetChannels: Array.isArray(raw?.targetChannels) + ? raw.targetChannels.filter((item): item is string => typeof item === "string") + : [], + hardConstraints: Array.isArray(raw?.hardConstraints) + ? raw.hardConstraints.filter((item): item is string => typeof item === "string") + : [], + }; +} + +function areStringArraysEqual(left: string[], right: string[]): boolean { + if (left.length !== right.length) { + return false; + } + + return left.every((value, index) => value === right[index]); +} + +function areBriefConstraintsEqual(left: AgentBriefConstraints, right: AgentBriefConstraints): boolean { + return ( + left.briefing === right.briefing && + left.audience === right.audience && + left.tone === right.tone && + areStringArraysEqual(left.targetChannels, right.targetChannels) && + areStringArraysEqual(left.hardConstraints, right.hardConstraints) + ); +} + function CompactList({ items }: { items: readonly string[] }) { return (