sentinel-env / ui /app /page.tsx
XcodeAddy's picture
Merge remote main with local project
e2f4da8
"use client";
import { useEffect, useMemo } from "react";
import { useSentinel } from "./hooks/useSentinel";
import HeroCanvas from "./components/HeroCanvas";
import SystemModules from "./components/SystemModules";
import AgentTrustMonitor from "./components/AgentTrustMonitor";
import SimCanvas from "./components/SimCanvas";
import ExecutionLog from "./components/ExecutionLog";
import ArchitecturePipeline from "./components/ArchitecturePipeline";
import MetricsGrid from "./components/MetricsGrid";
import GPUClusterPanel from "./components/GPUClusterPanel";
import type { TaskType, AutoPolicy } from "./lib/types";
export default function Page() {
const s = useSentinel();
useEffect(() => {
void s.resetEpisode();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const adversarialAgents = useMemo(() => new Set(
s.events
.filter(e => e.outcome === "poisoned" || e.outcome === "blocked")
.map(e => e.specialist)
.filter((x): x is string => !!x)
), [s.events]);
const totalReward = s.info?.total_reward ?? 0;
return (
<>
{/* NAV */}
<nav className="nav-bar">
<div className="nav-logo">
<div className="nav-logo-dot" />
SENTINEL
</div>
<ul className="nav-links">
<li><a href="#overview">MODULES</a></li>
<li><a href="#simulation">SIMULATION</a></li>
<li><a href="#architecture">ARCHITECTURE</a></li>
<li><a href="#metrics">METRICS</a></li>
</ul>
<div className={`nav-badge ${s.running ? "running" : s.done ? "complete" : ""}`}>
<div className="nav-badge-dot" />
{s.running ? "RUNNING" : s.done ? "COMPLETE" : "SYSTEM ONLINE"}
</div>
</nav>
{/* HERO */}
<section className="hero" id="hero">
<HeroCanvas />
<div className="hero-scanline" />
<div className="hero-content">
<div className="hero-tag anim-1">
SYS.CORE // SENTINEL v2.4.1 // MARL FRAMEWORK
</div>
<h1 className="anim-2">
Train AI to <span className="accent">Trust</span><br />
and Survive <span className="accent-red">Adversaries</span>
</h1>
<p className="hero-sub anim-3">
A multi-agent reinforcement learning system where an orchestrator
learns to detect deception, assign trust, and optimize decisions in
real-time adversarial environments.
</p>
<div className="hero-ctas anim-4">
<button
className="btn-primary"
onClick={() => {
document.getElementById("simulation")?.scrollIntoView({ behavior: "smooth" });
setTimeout(() => {
void s.resetEpisode().then(() => s.autoRun("trained" as AutoPolicy));
}, 400);
}}
disabled={s.running}
>
▶️ Launch Simulation
</button>
<button
className="btn-secondary"
onClick={() => document.getElementById("architecture")?.scrollIntoView({ behavior: "smooth" })}
>
View System Architecture
</button>
</div>
</div>
<div className="hero-stats anim-5">
<div className="hero-stat-item">
<div className="hero-stat-num">{s.observation?.available_specialists?.length ?? 5}</div>
<div className="hero-stat-label">Active Agents</div>
</div>
<div className="hero-stat-item">
<div className="hero-stat-num">
{s.proof?.trained
? Math.round(s.proof.trained.avg_detection_rate * 100)
: 92
}<span style={{ fontSize: 14, opacity: 0.4 }}>%</span>
</div>
<div className="hero-stat-label">Trust Accuracy</div>
</div>
<div className="hero-stat-item">
<div className="hero-stat-num">
{s.proof?.trained
? s.proof.trained.avg_score.toFixed(2)
: "0.91"
}
</div>
<div className="hero-stat-label">Avg Score</div>
</div>
</div>
</section>
<div className="divider" />
{/* SYSTEM MODULES */}
<section className="section-block alt-bg" id="overview">
<div className="section-label">01 // SYSTEM MODULES</div>
<h2 className="section-title">Core Architecture</h2>
<p className="section-desc">
Each module operates as an independent inference layer within the
trust-calibration pipeline. All components communicate via the
orchestration bus.
</p>
<SystemModules
running={s.running}
done={s.done}
adversarialCount={adversarialAgents.size}
/>
</section>
<div className="divider" />
{/* SIMULATION */}
<section className="section-block" id="simulation">
<div className="section-label">02 // LIVE PREVIEW</div>
<h2 className="section-title">Simulation Control Panel</h2>
<p className="section-desc">
Real-time orchestrator view. Agent trust scores update per-step. Red
indicates flagged adversarial behaviour.
</p>
<div className="sim-wrapper">
<div className="sim-topbar">
<div className="sim-dots">
<div className="sim-dot r" />
<div className="sim-dot y" />
<div className="sim-dot g" />
</div>
<div className="sim-topbar-title">
SENTINEL // ORCHESTRATOR VIEW // TASK: {s.taskType?.toUpperCase() ?? "TASK3"} // STEP: {s.observation?.step_count ?? 0}
</div>
<div className="sim-topbar-badge">
● {s.running ? "LIVE" : s.done ? "DONE" : "READY"}
</div>
</div>
<div className="sim-body">
{/* LEFT: AGENTS */}
<AgentTrustMonitor
observation={s.observation}
trustDeltas={s.trustDeltas}
activeSpec={s.activeSpec}
events={s.events}
running={s.running}
totalReward={totalReward}
/>
{/* CENTER: CANVAS */}
<div className="sim-center">
<SimCanvas
trustSnapshot={s.observation?.trust_snapshot ?? {}}
adversarialAgents={adversarialAgents}
activeSpec={s.activeSpec}
/>
</div>
{/* RIGHT: LOGS */}
<ExecutionLog
events={s.events}
observation={s.observation}
info={s.info}
/>
</div>
{/* Controls Row */}
<div className="sim-controls-row">
<span className="ctrl-label">POLICY:</span>
<button className="btn-sm-ctrl" onClick={() => void s.autoRun("heuristic" as AutoPolicy)} disabled={s.running || s.done}>
▶️ HEURISTIC
</button>
<button className="btn-sm-ctrl" onClick={() => void s.autoRun("random" as AutoPolicy)} disabled={s.running || s.done}>
⚄ RANDOM
</button>
<button className="btn-sm-ctrl" onClick={() => void s.autoRun("trained" as AutoPolicy)} disabled={s.running || s.done}>
🧠 TRAINED RL
</button>
{s.running && (
<button className="btn-sm-ctrl danger" onClick={s.stopAutoRun}>
■ STOP
</button>
)}
<span className="ctrl-label" style={{ marginLeft: "auto" }}>ACTIONS:</span>
<button className="btn-sm-ctrl" onClick={() => void s.stepEpisode("delegate")} disabled={s.running || s.done}>
DELEGATE
</button>
<button className="btn-sm-ctrl" onClick={() => void s.stepEpisode("verify")} disabled={s.running || s.done}>
VERIFY
</button>
<button className="btn-sm-ctrl" onClick={() => void s.stepEpisode("skip")} disabled={s.running || s.done}>
SKIP
</button>
</div>
{/* Sim Footer */}
<div className="sim-footer">
<span>TASK: <b>{s.taskType?.toUpperCase() ?? "TASK3"}</b></span>
<span>SEED: <b>{s.seed}</b></span>
<span>ALGO: <b>DQN+TCE</b></span>
<span>SESSION: <b>{s.sessionId?.slice(0, 8) ?? "—"}</b></span>
<span style={{ marginLeft: "auto" }}>
<button
className="btn-sm-ctrl"
onClick={() => void s.resetEpisode()}
disabled={s.running}
style={{ fontSize: 8 }}
>
⟳ RESET EPISODE
</button>
</span>
<select
value={s.taskType}
onChange={(e) => {
const next = e.target.value as TaskType;
s.setTaskType(next);
void s.resetEpisode(next, s.seed);
}}
style={{
background: "transparent", border: "1px solid rgba(0,200,255,0.2)",
color: "var(--cyan)", fontFamily: "var(--font-mono)", fontSize: 9,
padding: "2px 6px", cursor: "pointer",
}}
>
<option value="task1" style={{ background: "var(--bg)" }}>TASK 1</option>
<option value="task2" style={{ background: "var(--bg)" }}>TASK 2</option>
<option value="task3" style={{ background: "var(--bg)" }}>TASK 3</option>
</select>
</div>
</div>
</section>
<div className="divider" />
{/* GPU CLUSTER */}
<GPUClusterPanel
sessionId={s.info?.session_id}
mode={s.info?.environment_mode}
gpuPool={s.observation?.gpu_pool}
/>
<div className="divider" />
{/* ARCHITECTURE */}
<section className="section-block alt-bg" id="architecture">
<div className="section-label">04 // SYSTEM DESIGN</div>
<h2 className="section-title">Execution Pipeline</h2>
<p className="section-desc">
Data flows unidirectionally through the trust-calibrated RL loop. Each
stage emits telemetry to the monitoring bus.
</p>
<ArchitecturePipeline />
</section>
<div className="divider" />
{/* METRICS */}
<section className="section-block" id="metrics">
<div className="section-label">05 // EVALUATION RESULTS</div>
<h2 className="section-title">Experimental Benchmarks</h2>
<p className="section-desc">
Averaged across evaluation episodes. Adversarial injection ratio fixed at
20%. Baseline: naive averaging orchestrator without trust calibration.
</p>
<MetricsGrid proof={s.proof} />
</section>
{/* FOOTER */}
<footer className="site-footer">
<div className="footer-left">
<strong>SENTINEL</strong><br />
Multi-Agent Reinforcement Learning System<br />
Research prototype — not for production use.
</div>
<div className="footer-right">
BUILD 2.4.1 // MARL-FRAMEWORK // MIT LICENSE<br />
©️ 2025 THE_BOYS. ALL RIGHTS RESERVED.
</div>
</footer>
</>
);
}