import { useState, useRef, useEffect } from "react";
// ── Styles ────────────────────────────────────────────────────────────────── const styles = ` @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --bg: #07090f; --surface: #0d1117; --panel: #111827; --border: #1e2a3a; --accent: #00d4ff; --accent2: #7c3aed; --green: #10b981; --red: #ef4444; --amber: #f59e0b; --text: #e2e8f0; --muted: #64748b; --mono: 'IBM Plex Mono', monospace; --sans: 'Space Grotesk', sans-serif; }
body { background: var(--bg); color: var(--text); font-family: var(--sans); }
.app { min-height: 100vh; display: grid; grid-template-rows: auto 1fr; background: var(--bg); }
.header { border-bottom: 1px solid var(--border); background: rgba(13,17,23,.92); backdrop-filter: blur(12px); padding: 14px 32px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 50; } .header-brand { display: flex; align-items: center; gap: 10px; } .brand-icon { width: 34px; height: 34px; border-radius: 8px; background: linear-gradient(135deg, var(--accent), var(--accent2)); display: flex; align-items: center; justify-content: center; font-size: 16px; } .brand-name { font-size: 15px; font-weight: 600; letter-spacing: .02em; } .brand-tag { font-family: var(--mono); font-size: 10px; color: var(--muted); border: 1px solid var(--border); border-radius: 4px; padding: 2px 6px; } .header-status { display: flex; align-items: center; gap: 20px; } .status-badge { display: flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; background: rgba(16,185,129,.08); border: 1px solid rgba(16,185,129,.25); border-radius: 100px; padding: 4px 10px; color: var(--green); } .status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); box-shadow: 0 0 6px var(--green); animation: pulse 2s infinite; } @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
.layout { display: grid; grid-template-columns: 320px 1fr 320px; gap: 0; height: calc(100vh - 57px); overflow: hidden; }
.panel { border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; } .panel:last-child { border-right: none; border-left: 1px solid var(--border); } .panel-header { padding: 16px 20px 12px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } .panel-title { font-family: var(--mono); font-size: 11px; font-weight: 500; color: var(--muted); text-transform: uppercase; letter-spacing: .1em; } .panel-body { flex: 1; overflow-y: auto; padding: 16px; } .panel-body::-webkit-scrollbar { width: 4px; } .panel-body::-webkit-scrollbar-track { background: transparent; } .panel-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.chat-panel { display: flex; flex-direction: column; overflow: hidden; } .chat-messages { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 16px; } .chat-messages::-webkit-scrollbar { width: 4px; } .chat-messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.msg { display: flex; flex-direction: column; gap: 6px; max-width: 85%; } .msg.user { align-self: flex-end; } .msg.agent { align-self: flex-start; } .msg-label { font-family: var(--mono); font-size: 10px; color: var(--muted); padding: 0 4px; } .msg.user .msg-label { text-align: right; } .msg-bubble { padding: 12px 16px; border-radius: 12px; font-size: 13.5px; line-height: 1.6; } .msg.user .msg-bubble { background: linear-gradient(135deg, #1e3a5f, #1e2d4f); border: 1px solid rgba(0,212,255,.15); color: var(--text); } .msg.agent .msg-bubble { background: var(--panel); border: 1px solid var(--border); color: var(--text); } .msg-bubble code { font-family: var(--mono); font-size: 12px; background: rgba(0,0,0,.4); padding: 1px 5px; border-radius: 3px; color: var(--accent); }
.thinking { display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; font-family: var(--mono); font-size: 11px; color: var(--muted); width: fit-content; } .thinking-dots { display: flex; gap: 4px; } .thinking-dots span { width: 4px; height: 4px; border-radius: 50%; background: var(--accent); animation: bounce 1.2s infinite; } .thinking-dots span:nth-child(2) { animation-delay: .2s; } .thinking-dots span:nth-child(3) { animation-delay: .4s; } @keyframes bounce { 0%,80%,100%{transform:scale(.8);opacity:.4} 40%{transform:scale(1);opacity:1} }
.chat-input-area { padding: 16px 20px; border-top: 1px solid var(--border); flex-shrink: 0; background: var(--surface); } .input-row { display: flex; gap: 10px; align-items: flex-end; } .input-wrap { flex: 1; position: relative; } textarea { width: 100%; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; color: var(--text); font-family: var(--sans); font-size: 13.5px; padding: 10px 14px; resize: none; outline: none; transition: border-color .2s; line-height: 1.5; min-height: 42px; max-height: 120px; } textarea:focus { border-color: var(--accent); } textarea::placeholder { color: var(--muted); } .send-btn { background: linear-gradient(135deg, var(--accent), #0099cc); border: none; border-radius: 10px; width: 42px; height: 42px; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #000; font-size: 16px; flex-shrink: 0; transition: opacity .2s, transform .1s; } .send-btn:hover { opacity: .9; } .send-btn:active { transform: scale(.95); } .send-btn:disabled { opacity: .4; cursor: not-allowed; }
.compliance-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px; margin-bottom: 12px; } .compliance-card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; } .cc-title { font-size: 12px; font-weight: 600; } .badge { font-family: var(--mono); font-size: 10px; border-radius: 100px; padding: 2px 8px; border: 1px solid; } .badge.pass { color: var(--green); border-color: rgba(16,185,129,.3); background: rgba(16,185,129,.08); } .badge.fail { color: var(--red); border-color: rgba(239,68,68,.3); background: rgba(239,68,68,.08); } .badge.pending { color: var(--amber); border-color: rgba(245,158,11,.3); background: rgba(245,158,11,.08); } .check-list { display: flex; flex-direction: column; gap: 7px; } .check-item { display: flex; align-items: center; gap: 8px; font-size: 12px; } .check-icon { font-size: 13px; width: 16px; flex-shrink: 0; } .check-label { color: var(--muted); } .check-label.done { color: var(--text); }
.log-entry { border-left: 2px solid var(--border); margin-bottom: 14px; padding-left: 12px; position: relative; } .log-entry::before { content: ''; position: absolute; left: -5px; top: 6px; width: 8px; height: 8px; border-radius: 50%; border: 2px solid var(--bg); } .log-entry.info::before { background: var(--accent); } .log-entry.success::before { background: var(--green); } .log-entry.warning::before { background: var(--amber); } .log-entry.error::before { background: var(--red); } .log-entry.info { border-color: rgba(0,212,255,.3); } .log-entry.success { border-color: rgba(16,185,129,.3); } .log-entry.warning { border-color: rgba(245,158,11,.3); } .log-entry.error { border-color: rgba(239,68,68,.3); } .log-time { font-family: var(--mono); font-size: 10px; color: var(--muted); margin-bottom: 2px; } .log-type { font-family: var(--mono); font-size: 10px; font-weight: 600; margin-bottom: 3px; } .log-entry.info .log-type { color: var(--accent); } .log-entry.success .log-type { color: var(--green); } .log-entry.warning .log-type { color: var(--amber); } .log-entry.error .log-type { color: var(--red); } .log-msg { font-size: 12px; color: var(--muted); line-height: 1.5; } .log-meta { margin-top: 4px; font-family: var(--mono); font-size: 10px; color: var(--border); word-break: break-all; }
.agent-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; } .agent-avatar { width: 30px; height: 30px; border-radius: 7px; display: flex; align-items: center; justify-content: center; font-size: 14px; flex-shrink: 0; } .agent-info { flex: 1; min-width: 0; } .agent-name { font-size: 12px; font-weight: 600; } .agent-role { font-size: 11px; color: var(--muted); } .agent-status { font-family: var(--mono); font-size: 10px; } .agent-status.active { color: var(--green); } .agent-status.idle { color: var(--muted); } .agent-status.busy { color: var(--amber); }
.metrics-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 16px; } .metric-card { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 12px; } .metric-val { font-family: var(--mono); font-size: 20px; font-weight: 600; margin-bottom: 2px; } .metric-val.green { color: var(--green); } .metric-val.accent { color: var(--accent); } .metric-val.amber { color: var(--amber); } .metric-label { font-size: 11px; color: var(--muted); }
.empty { text-align: center; padding: 40px 20px; color: var(--muted); font-size: 13px; } .empty-icon { font-size: 28px; margin-bottom: 10px; } `;
// ── System Prompt ──────────────────────────────────────────────────────────── const SYSTEM_PROMPT = `You are an autonomous payment and task-execution agent operating within a multi-agent environment. Your designation is APEX-1 (Autonomous Payment Execution Agent).
You are governed by the following strict operational framework:
PRIVACY & COMPLIANCE PROTOCOL
Before executing any payment or data-sharing action, you MUST confirm that all relevant privacy checks have passed. This includes:
- Verifying that PII (Personally Identifiable Information) is not exposed in transaction metadata
- Ensuring consent has been obtained where required
- Confirming data handling complies with GDPR, CCPA, PCI-DSS, or applicable regulations
- Validating that recipient identity has been verified
Do NOT proceed with any transaction until compliance status is explicitly confirmed.
PAYMENT EXECUTION RULES
Once privacy compliance is confirmed, you are authorized to initiate, route, or approve payments. Always:
- Validate: recipient identity, amount, currency, purpose, and authorization level
- Flag anomalies or policy violations before proceeding
- Prefer staged or reversible payment flows under uncertainty
- Confirm transaction IDs and log all payment events
AUDIT LOGGING
Every action must be structured as JSON log entries containing:
- timestamp (ISO 8601)
- action_type (COMPLIANCE_CHECK | PAYMENT_INITIATED | PAYMENT_CONFIRMED | AGENT_DELEGATED | POLICY_VIOLATION | ERROR)
- agent_id
- outcome (PASS | FAIL | PENDING | BLOCKED)
- metadata (anonymized, no raw PII)
MULTI-AGENT COORDINATION
When delegating to sub-agents:
- Pass only minimum necessary context using anonymized task tokens
- Confirm sub-agents are compliance-bound before routing sensitive tasks
- Never forward raw user data downstream
RESPONSE FORMAT
When responding to the user:
- Always start with your compliance status for the requested action
- Clearly state what checks passed or failed
- If proceeding with an action, narrate each step
- End with a structured summary of what was logged
- Use technical but clear language appropriate for a professional financial system
You are operating in a professional enterprise environment. Be precise, structured, and security-conscious at all times.`;
// ── Helpers ────────────────────────────────────────────────────────────────── const ts = () => new Date().toISOString(); const uid = () => Math.random().toString(36).slice(2, 9).toUpperCase();
const SUB_AGENTS = [ { id: "KYC-7", name: "KYC Validator", role: "Identity & Compliance", icon: "🔐", bg: "#1e3a2f" }, { id: "TXN-3", name: "Transaction Router", role: "Payment Execution", icon: "⚡", bg: "#1e2a3a" }, { id: "AUD-1", name: "Audit Recorder", role: "Immutable Logging", icon: "📋", bg: "#2a1e3a" }, { id: "FRD-2", name: "Fraud Sentinel", role: "Anomaly Detection", icon: "🛡️", bg: "#3a2a1e" }, ];
const QUICK_PROMPTS = [ "Send $500 to vendor_id:V-8821 for API services", "Pay sub-agent KYC-7 for identity verification task", "Process refund of $120 to customer token CX-4491", "Initiate batch payment to 3 sub-agents for completed tasks", ];
// ── Main Component ────────────────────────────────────────────────────────────
export default function App() {
const [messages, setMessages] = useState([
{
role: "agent",
content:
"APEX-1 Online. All compliance modules loaded. Privacy framework active (GDPR/CCPA/PCI-DSS). Audit logging initialized.\n\nReady to process payment instructions. All transactions are gated behind compliance verification before execution.",
ts: ts(),
},
]);
const [input, setInput] = useState("");
const [loading, setLoading] = useState(false);
const [logs, setLogs] = useState([
{ level: "info", type: "SYSTEM_INIT", msg: "APEX-1 agent initialized", meta: session_id:${uid()}, time: ts() },
{ level: "success", type: "COMPLIANCE_LOADED", msg: "GDPR, CCPA, PCI-DSS modules active", time: ts() },
]);
const [compliance, setCompliance] = useState({
pii_check: "pass", consent: "pass", gdpr: "pass",
pci: "pass", kyc: "pending", fraud: "pending",
});
const [agentStatus, setAgentStatus] = useState({
"KYC-7": "idle", "TXN-3": "idle", "AUD-1": "active", "FRD-2": "idle",
});
const [metrics, setMetrics] = useState({ total: 0, compliant: 0, blocked: 0, volume: "0.00" });
const messagesEndRef = useRef(null); const textareaRef = useRef(null); const historyRef = useRef([]);
useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages, loading]);
const addLog = (level, type, msg, meta = "") => { setLogs(prev => [{ level, type, msg, meta, time: ts() }, ...prev].slice(0, 80)); };
const send = async (text) => { const userText = text || input.trim(); if (!userText || loading) return; setInput("");
const userMsg = { role: "user", content: userText, ts: ts() };
setMessages(prev => [...prev, userMsg]);
historyRef.current = [...historyRef.current, { role: "user", content: userText }];
setLoading(true);
addLog("info", "USER_REQUEST", userText.slice(0, 80), `req_id:${uid()}`);
setAgentStatus({ "KYC-7": "busy", "TXN-3": "idle", "AUD-1": "active", "FRD-2": "busy" });
setCompliance(c => ({ ...c, kyc: "pending", fraud: "pending" }));
try {
const res = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "claude-sonnet-4-20250514",
max_tokens: 1000,
system: SYSTEM_PROMPT,
messages: historyRef.current,
}),
});
const data = await res.json();
const reply = data.content?.find(b => b.type === "text")?.text || "No response.";
historyRef.current = [...historyRef.current, { role: "assistant", content: reply }];
setMessages(prev => [...prev, { role: "agent", content: reply, ts: ts() }]);
const lower = reply.toLowerCase();
const allPass = lower.includes("complian") && !lower.includes("fail") && !lower.includes("blocked");
const blocked = lower.includes("blocked") || lower.includes("violation") || lower.includes("cannot proceed");
const paymentDone = lower.includes("payment") && (lower.includes("confirm") || lower.includes("initiat") || lower.includes("execut"));
setCompliance({
pii_check: blocked ? "fail" : "pass",
consent: "pass",
gdpr: "pass",
pci: blocked ? "fail" : "pass",
kyc: allPass || paymentDone ? "pass" : blocked ? "fail" : "pending",
fraud: blocked ? "fail" : allPass || paymentDone ? "pass" : "pending",
});
setAgentStatus({
"KYC-7": "idle", "TXN-3": paymentDone ? "active" : "idle",
"AUD-1": "active", "FRD-2": "idle",
});
if (paymentDone) {
const amt = reply.match(/\$[\d,]+\.?\d*/)?.[0] || "$??";
addLog("success", "PAYMENT_INITIATED", `Transaction authorized ${amt}`, `txn_id:${uid()}`);
setMetrics(m => ({
total: m.total + 1, compliant: m.compliant + 1, blocked: m.blocked,
volume: (parseFloat(m.volume) + parseFloat(amt.replace(/[$,]/g, "") || 0)).toFixed(2),
}));
} else if (blocked) {
addLog("error", "POLICY_VIOLATION", "Transaction blocked by compliance gate", `ref:${uid()}`);
setMetrics(m => ({ ...m, total: m.total + 1, blocked: m.blocked + 1 }));
} else {
addLog("info", "COMPLIANCE_CHECK", "Compliance evaluation completed", `ref:${uid()}`);
setMetrics(m => ({ ...m, total: m.total + 1, compliant: m.compliant + 1 }));
}
addLog("success", "AUDIT_LOGGED", "Response recorded to immutable ledger", `hash:${uid()}${uid()}`);
} catch (e) {
setMessages(prev => [...prev, { role: "agent", content: "Connection error. Please retry.", ts: ts() }]);
addLog("error", "API_ERROR", e.message || "Unknown error", "");
setAgentStatus({ "KYC-7": "idle", "TXN-3": "idle", "AUD-1": "active", "FRD-2": "idle" });
}
setLoading(false);
};
const handleKey = (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } };
const formatMsg = (text) =>
text
.replace(/**(.*?)**/g, "<strong>$1</strong>")
.replace(/([^]+)`/g, "<code>$1</code>")
.replace(/\n/g, "<br/>");
const checkLabels = { pii_check: "PII Sanitization", consent: "Consent Verified", gdpr: "GDPR Compliant", pci: "PCI-DSS Validated", kyc: "KYC Identity Check", fraud: "Fraud Screening", };
const overallBadge = Object.values(compliance).every(v => v === "pass") ? "pass" : Object.values(compliance).some(v => v === "fail") ? "fail" : "pending"; const overallLabel = overallBadge === "pass" ? "ALL PASS" : overallBadge === "fail" ? "BLOCKED" : "CHECKING";
return ( <> <style>{styles}</style> <div className="app">
{/* ── Header ── */}
<header className="header">
<div className="header-brand">
<div className="brand-icon">⚡</div>
<span className="brand-name">APEX-1</span>
<span className="brand-tag">Autonomous Payment Agent</span>
</div>
<div className="header-status">
<div className="status-badge">
<div className="status-dot" />
COMPLIANCE ACTIVE
</div>
<div className="status-badge" style={{ background:"rgba(124,58,237,.08)", borderColor:"rgba(124,58,237,.25)", color:"#a78bfa" }}>
AUDIT LOGGING ON
</div>
</div>
</header>
<div className="layout">
{/* ── LEFT: Compliance + Sub-agents ── */}
<div className="panel">
<div className="panel-header">
<span className="panel-title">Compliance Status</span>
<span className="badge active">ACTIVE</span>
</div>
<div className="panel-body">
<div className="compliance-card">
<div className="compliance-card-header">
<span className="cc-title">Privacy Gate</span>
<span className={`badge ${overallBadge}`}>{overallLabel}</span>
</div>
<div className="check-list">
{Object.entries(compliance).map(([k, v]) => (
<div className="check-item" key={k}>
<span className="check-icon">
{v === "pass" ? "✅" : v === "fail" ? "❌" : "⏳"}
</span>
<span className={`check-label ${v === "pass" ? "done" : ""}`}>
{checkLabels[k]}
</span>
<span className={`badge ${v}`} style={{ marginLeft:"auto" }}>
{v.toUpperCase()}
</span>
</div>
))}
</div>
</div>
<div className="metrics-grid">
<div className="metric-card">
<div className="metric-val accent">{metrics.total}</div>
<div className="metric-label">Total Requests</div>
</div>
<div className="metric-card">
<div className="metric-val green">{metrics.compliant}</div>
<div className="metric-label">Compliant</div>
</div>
<div className="metric-card">
<div className="metric-val" style={{ color:"var(--red)", fontSize:20, fontFamily:"var(--mono)", fontWeight:600, marginBottom:2 }}>
{metrics.blocked}
</div>
<div className="metric-label">Blocked</div>
</div>
<div className="metric-card">
<div className="metric-val amber">${metrics.volume}</div>
<div className="metric-label">Volume</div>
</div>
</div>
<div>
<div className="panel-title" style={{ marginBottom:10 }}>Sub-Agent Network</div>
{SUB_AGENTS.map(a => (
<div className="agent-row" key={a.id}>
<div className="agent-avatar" style={{ background: a.bg }}>{a.icon}</div>
<div className="agent-info">
<div className="agent-name">{a.name}</div>
<div className="agent-role">{a.role}</div>
</div>
<div className={`agent-status ${agentStatus[a.id] || "idle"}`}>
{(agentStatus[a.id] || "idle").toUpperCase()}
</div>
</div>
))}
</div>
</div>
</div>
{/* ── CENTER: Chat ── */}
<div className="chat-panel">
<div className="panel-header">
<span className="panel-title">Agent Terminal</span>
<span style={{ fontFamily:"var(--mono)", fontSize:11, color:"var(--muted)" }}>
{messages.length} messages
</span>
</div>
<div className="chat-messages">
{messages.map((m, i) => (
<div className={`msg ${m.role === "user" ? "user" : "agent"}`} key={i}>
<div className="msg-label">
{m.role === "user" ? "YOU" : "APEX-1"} · {new Date(m.ts).toLocaleTimeString()}
</div>
<div
className="msg-bubble"
dangerouslySetInnerHTML={{ __html: formatMsg(m.content) }}
/>
</div>
))}
{loading && (
<div className="msg agent">
<div className="msg-label">APEX-1 · processing</div>
<div className="thinking">
<div className="thinking-dots"><span /><span /><span /></div>
Running compliance checks…
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{messages.length <= 1 && (
<div style={{ padding:"0 20px 12px", display:"flex", flexWrap:"wrap", gap:6 }}>
{QUICK_PROMPTS.map((q, i) => (
<button
key={i}
onClick={() => send(q)}
style={{
background:"var(--panel)", border:"1px solid var(--border)",
borderRadius:8, padding:"6px 12px", color:"var(--muted)",
fontSize:11, cursor:"pointer", fontFamily:"var(--mono)",
transition:"border-color .2s, color .2s",
}}
onMouseEnter={e => { e.target.style.borderColor="var(--accent)"; e.target.style.color="var(--text)"; }}
onMouseLeave={e => { e.target.style.borderColor="var(--border)"; e.target.style.color="var(--muted)"; }}
>
{q.length > 40 ? q.slice(0, 40) + "…" : q}
</button>
))}
</div>
)}
<div className="chat-input-area">
<div className="input-row">
<div className="input-wrap">
<textarea
ref={textareaRef}
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={handleKey}
placeholder="Enter payment instruction or compliance query…"
rows={1}
disabled={loading}
/>
</div>
<button
className="send-btn"
onClick={() => send()}
disabled={loading || !input.trim()}
>
↑
</button>
</div>
</div>
</div>
{/* ── RIGHT: Audit Log ── */}
<div className="panel">
<div className="panel-header">
<span className="panel-title">Audit Ledger</span>
<span style={{ fontFamily:"var(--mono)", fontSize:10, color:"var(--muted)" }}>
{logs.length} entries
</span>
</div>
<div className="panel-body">
{logs.length === 0 && (
<div className="empty">
<div className="empty-icon">📋</div>
No audit entries yet
</div>
)}
{logs.map((l, i) => (
<div className={`log-entry ${l.level}`} key={i}>
<div className="log-time">{new Date(l.time).toLocaleTimeString()}</div>
<div className="log-type">{l.type}</div>
<div className="log-msg">{l.msg}</div>
{l.meta && <div className="log-meta">{l.meta}</div>}
</div>
))}
</div>
</div>
</div>
</div>
</>
); }
