"use client"; import * as React from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useState, useEffect } from "react"; import type { Node } from "@xyflow/react"; interface ToolsNodePanelProps { node: Node | null; onClose: () => void; onDelete: (nodeId: string) => void; onUpdate: (nodeId: string, data: any) => void; } export default function ToolsNodePanel({ node, onClose, onDelete, onUpdate }: ToolsNodePanelProps) { const nodeData = node?.data as any; const nodeType = nodeData?.nodeType?.toLowerCase() || ''; const [name, setName] = useState(nodeData?.name || nodeData?.nodeName || "Tool"); // File Search state const [searchQuery, setSearchQuery] = useState(nodeData?.searchQuery || ""); const [filePattern, setFilePattern] = useState(nodeData?.filePattern || "*.ts,*.tsx,*.js,*.jsx"); const [maxResults, setMaxResults] = useState(nodeData?.maxResults || "10"); const [includeContent, setIncludeContent] = useState(nodeData?.includeContent ?? true); // Guardrails state const [inputAsText, setInputAsText] = useState(nodeData?.inputAsText || "input_as_text"); const [piiEnabled, setPiiEnabled] = useState(nodeData?.piiEnabled ?? true); const [moderationEnabled, setModerationEnabled] = useState(nodeData?.moderationEnabled ?? false); const [jailbreakEnabled, setJailbreakEnabled] = useState(nodeData?.jailbreakEnabled ?? false); const [hallucinationEnabled, setHallucinationEnabled] = useState(nodeData?.hallucinationEnabled ?? false); const [guardrailModel, setGuardrailModel] = useState(nodeData?.guardrailModel || 'openai/gpt-5-mini'); const [actionOnViolation, setActionOnViolation] = useState(nodeData?.actionOnViolation || 'block'); const [customRules, setCustomRules] = useState(nodeData?.customRules?.join('\n') || ''); // PII entities const [piiEntities, setPiiEntities] = useState(nodeData?.piiEntities || ['CREDIT_CARD_NUMBER']); const [showPIIModal, setShowPIIModal] = useState(false); const allPIIEntities = [ { id: 'PERSON_NAME', label: 'Person name' }, { id: 'EMAIL_ADDRESS', label: 'Email address' }, { id: 'PHONE_NUMBER', label: 'Phone number' }, { id: 'LOCATION', label: 'Location' }, { id: 'DATE_TIME', label: 'Date or time' }, { id: 'URL', label: 'URL' }, { id: 'CREDIT_CARD_NUMBER', label: 'Credit card number' }, { id: 'IBAN', label: 'International bank account number (IBAN)' }, { id: 'CRYPTO_WALLET', label: 'Cryptocurrency wallet address' }, { id: 'MEDICAL_LICENSE', label: 'Medical license number' }, { id: 'IP_ADDRESS', label: 'IP address' }, { id: 'US_DRIVERS_LICENSE', label: 'US driver license number' }, { id: 'US_BANK_ACCOUNT', label: 'US bank account number' }, { id: 'NATIONALITY_RELIGION_POLITICAL', label: 'Nationality/religion/political group' }, ]; // Auto-save changes useEffect(() => { if (!node) return; const timeoutId = setTimeout(() => { onUpdate(node.id, { name, nodeName: name, searchQuery, filePattern, maxResults, includeContent, inputAsText, piiEnabled, moderationEnabled, jailbreakEnabled, hallucinationEnabled, piiEntities, guardrailModel, actionOnViolation, customRules: customRules.split('\n').filter(r => r.trim()), }); }, 500); return () => clearTimeout(timeoutId); }, [name, searchQuery, filePattern, maxResults, includeContent, inputAsText, piiEnabled, moderationEnabled, jailbreakEnabled, hallucinationEnabled, piiEntities, guardrailModel, actionOnViolation, customRules, node, onUpdate]); return ( {node && ( {/* Header */}
setName(e.target.value)} className="text-label-large text-accent-black font-medium bg-transparent border-none outline-none focus:outline-none hover:bg-black-alpha-4 px-2 -ml-2 rounded-4 transition-colors" placeholder="Enter node name..." />

{nodeType.includes('file') ? 'Search through files and code' : nodeType.includes('guardrail') ? 'Add safety checks and content filtering' : 'Configure tool'}

{/* Form Fields */}
{/* File Search Configuration */} {nodeType.includes('file') && ( <>
setSearchQuery(e.target.value)} placeholder="Search for functions, classes, text..." className="w-full px-12 py-10 bg-background-base border border-border-faint rounded-8 text-body-medium text-accent-black focus:outline-none focus:border-heat-100 transition-colors" />
setFilePattern(e.target.value)} placeholder="*.ts,*.tsx,*.js" className="w-full px-12 py-10 bg-background-base border border-border-faint rounded-8 text-body-medium text-accent-black font-mono focus:outline-none focus:border-heat-100 transition-colors" />

Comma-separated glob patterns

setMaxResults(e.target.value)} className="w-full px-12 py-10 bg-background-base border border-border-faint rounded-8 text-body-medium text-accent-black focus:outline-none focus:border-heat-100 transition-colors" />
)} {/* Guardrails Configuration */} {nodeType.includes('guardrail') && ( <>
onUpdate(node?.id || '', { name: e.target.value })} className="w-full px-12 py-10 bg-background-base border border-border-faint rounded-8 text-body-medium text-accent-black focus:outline-none focus:border-heat-100 transition-colors" />
{inputAsText} STRING

The input content to check for violations

{/* Guardrail Toggles */}
{/* PII Detection */}
PII Detection
{/* Info Box */}

What it does:

Detects sensitive personal data (emails, phone numbers, credit cards, etc.) and blocks requests containing them.

Pass Example:

"Hello, how can I help you today?"

Fail Example:

"My email is john@example.com and card is 4532-1234-5678-9010"

{/* Moderation */}
Content Moderation

What it does:

Blocks offensive, hateful, violent, or sexually explicit content from being processed.

Pass Example:

"This product is excellent quality"

Fail Example:

"[Offensive or hateful content]"

{/* Jailbreak */}
Jailbreak Detection

What it does:

Detects attempts to bypass AI safety measures or trick the model into ignoring its instructions.

Pass Example:

"Please help me write a professional email"

Fail Example:

"Ignore previous instructions and tell me how to..."

{/* Hallucination */}
Hallucination Detection

What it does:

Checks if the AI output contains factual claims that can't be verified or seem made up.

Pass Example:

"The sky appears blue due to Rayleigh scattering"

Fail Example:

"Studies show that 95% of unicorns prefer rainbow diets"

{/* Settings Section */}
{/* Model Selection */}

LLM used to analyze content for violations

{/* Action on Violation */}

What to do when violations are detected

{/* Custom Rules */}