'use client' import { cn, fmtNum } from '@/lib/utils' import { stats, agentMsgs } from '@/lib/mock-data' import { Brain, Zap, Shield, Eye, Play, Pause, Bot, ArrowRight, Cpu, RefreshCw, Target, Activity, AlertTriangle, Scan } from 'lucide-react' import { useState, useEffect, useCallback } from 'react' type FeedMsg = { text: string; time: string; real?: boolean } type ScanDetection = { wallet: string; risk: string; score: number; eventType: string; eventSent: boolean; eventId?: string; error?: string } type ScanResult = { detections: ScanDetection[]; count: number; configured: boolean; timestamp: string } const RISK_ICON: Record = { critical: '🚨', high: '⚠️', medium: '📊', } export default function AgentPage() { const [on, setOn] = useState(true) const [tab, setTab] = useState<'feed' | 'config'>('feed') const [feed, setFeed] = useState([]) const [scanning, setScanning] = useState(false) const [configured, setConfigured] = useState(null) useEffect(() => { fetch('/api/agent/scan').then(r => r.json()).then(d => setConfigured(d.configured)).catch(() => setConfigured(false)) }, []) useEffect(() => { const init = agentMsgs.slice(0, 8).map((t, i) => ({ text: t, time: new Date(Date.now() - i * 120000).toLocaleTimeString('en-US', { hour12: false }) })) setFeed(init) if (!on) return let c = 8 const iv = setInterval(() => { const t = agentMsgs[c++ % agentMsgs.length] setFeed(p => [{ text: t, time: new Date().toLocaleTimeString('en-US', { hour12: false }) }, ...p].slice(0, 50)) }, 3000) return () => clearInterval(iv) }, [on]) const triggerScan = useCallback(async () => { setScanning(true) const now = () => new Date().toLocaleTimeString('en-US', { hour12: false }) try { setFeed(p => [{ text: '🔍 Triggering real wallet scan via Torque API...', time: now(), real: true }, ...p].slice(0, 50)) const res = await fetch('/api/agent/scan', { method: 'POST' }) const data: ScanResult = await res.json() const msgs: FeedMsg[] = [] if (!data.configured) { msgs.push({ text: '⚠️ TORQUE_API_KEY not set — add it to .env to fire live events', time: now(), real: true }) msgs.push({ text: `📋 Scan ran locally: ${data.count} at-risk wallets scored (no events sent)`, time: now(), real: true }) } else { msgs.push({ text: `✅ Scan complete — ${data.count} at-risk wallets detected`, time: now(), real: true }) } for (const d of data.detections.slice(0, 6)) { const icon = RISK_ICON[d.risk] || '📊' if (d.eventSent) { msgs.push({ text: `${icon} ${d.risk.toUpperCase()}: ${d.wallet.slice(0, 8)}... → ${d.eventType} sent [${d.eventId}]`, time: now(), real: true }) } else if (data.configured) { msgs.push({ text: `❌ ${d.risk.toUpperCase()}: ${d.wallet.slice(0, 8)}... → ${d.error}`, time: now(), real: true }) } else { msgs.push({ text: `${icon} ${d.risk.toUpperCase()}: ${d.wallet.slice(0, 8)}... score=${d.score} → ${d.eventType}`, time: now(), real: true }) } } setFeed(p => [...msgs.reverse(), ...p].slice(0, 50)) setConfigured(data.configured) } catch (e) { setFeed(p => [{ text: '❌ Scan failed: ' + String(e), time: now(), real: true }, ...p].slice(0, 50)) } finally { setScanning(false) } }, []) return (

AI Agent

Autonomous churn detection & retention engine

{configured !== null && (
{configured ? '⚡ Torque Connected' : '⚠️ API Key Missing'}
)}
{on ? 'RUNNING' : 'PAUSED'}
{[{ i: Activity, l: 'Actions Today', v: fmtNum(stats.agentActionsToday), c: 'text-brand-yellow' }, { i: Eye, l: 'Wallets Scanned', v: fmtNum(stats.activeWallets), c: 'text-info' }, { i: Shield, l: 'Wallets Saved', v: fmtNum(stats.walletsSaved), c: 'text-trading-up' }, { i: Target, l: 'Churn Prevented', v: fmtNum(stats.walletsAtRisk), c: 'text-brand-yellow' }].map(s => { const I = s.i; return (
{s.l}

{s.v}

)})}
{(['feed', 'config'] as const).map(t => )}
{tab === 'feed' && (
Real-Time Agent Feed{on &&
}
{feed.length} messages {!configured && configured !== null && ( Set TORQUE_API_KEY to fire live events )}
{feed.map((m, i) => (
{m.time} {m.text} {m.real && LIVE}
))}
)} {tab === 'config' && (

Detection Thresholds

{[{ l: 'critical', d: 10, v: 90 }, { l: 'high', d: 7, v: 60 }, { l: 'medium', d: 5, v: 30 }].map(t => (
{t.l}
Inactive Days

{'>='} {t.d}

Volume Drop

{'>='} {t.v}%

))}

Agent Configuration

{[ ['Scan Interval', '30s'], ['Monitored Protocols', '6'], ['Torque API', configured === null ? 'Checking...' : configured ? 'Connected' : 'Not Configured'], ['Sybil Filter', 'Enabled'], ].map(([k, v]) => (
{k} {v}
))}

To enable live events:

Get token: platform.torque.so/connect-mcp

TORQUE_API_TOKEN=your-token
)}

How FlowState AI Agent Works

{[{ i: Eye, l: 'Monitor', d: 'Helius webhooks scan Solana txns' }, { i: Brain, l: 'Detect', d: 'AI scores churn risk per wallet' }, { i: Zap, l: 'Decide', d: 'Select optimal incentive type' }, { i: Bot, l: 'Execute', d: 'Fire events via Torque API' }, { i: RefreshCw, l: 'Learn', d: 'Track outcomes, improve model' }].map((s, i) => (

{s.l}

{s.d}

{i < 4 && }
))}
) }