maias / index.html
molliexx99's picture
Please ensure that the hint/info boxes do not get obstructed by the edges of the timeline's area, ensure that these boxes are on-top/overlay any/all other visual elements on the web-page. - Initial Deployment
8f2503b verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-Agent Orchestration Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#10b981',
accent: '#8b5cf6',
warning: '#f59e0b',
danger: '#ef4444',
dark: '#1e293b',
light: '#f8fafc'
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #0f172a, #1e293b);
color: #f1f5f9;
}
.card {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(100, 116, 139, 0.3);
border-radius: 16px;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.25);
}
.card-header {
border-bottom: 1px solid rgba(148, 163, 184, 0.3);
padding-bottom: 1rem;
}
.btn {
font-weight: 600;
padding: 0.75rem 1.5rem;
border-radius: 12px;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.btn-primary {
background: linear-gradient(90deg, #3b82f6, #60a5fa);
color: white;
}
.btn-primary:hover {
background: linear-gradient(90deg, #2563eb, #3b82f6);
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(59, 130, 246, 0.3);
}
.btn-secondary {
background: rgba(100, 116, 139, 0.3);
color: #f1f5f9;
}
.btn-secondary:hover {
background: rgba(100, 116, 139, 0.5);
transform: translateY(-2px);
}
.btn-danger {
background: linear-gradient(90deg, #ef4444, #f87171);
color: white;
}
.btn-danger:hover {
background: linear-gradient(90deg, #dc2626, #ef4444);
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(239, 68, 68, 0.3);
}
.btn-icon {
margin-right: 0.5rem;
}
.toggle-container {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.toggle-container input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, #334155, #475569);
transition: .4s;
border-radius: 30px;
}
.toggle-slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .toggle-slider {
background: linear-gradient(90deg, #3b82f6, #60a5fa);
}
input:checked + .toggle-slider:before {
transform: translateX(30px);
}
.agent-timeline {
max-height: 500px;
overflow-y: auto;
padding-right: 10px;
}
.timeline-container {
min-height: 600px;
height: 100%;
display: flex;
flex-direction: column;
flex: 1;
}
.agent-timeline {
flex: 1;
overflow-y: auto;
}
.timeline-item {
position: relative;
padding-left: 40px;
margin-bottom: 30px;
}
.timeline-item:before {
content: '';
position: absolute;
left: 15px;
top: 0;
bottom: 0;
width: 2px;
background: linear-gradient(to bottom, #3b82f6, #94a3b8);
}
.timeline-item:last-child:before {
height: 20px;
}
.avatar {
position: absolute;
left: -15px;
top: 0;
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 14px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 2;
}
.collapsible-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.collapsible-content.active {
max-height: 500px;
}
.decision-card {
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 16px;
overflow: hidden;
}
.decision-card:hover {
transform: translateY(-3px);
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}
.tool-call {
background: rgba(255, 255, 255, 0.05);
border-left: 3px solid #3b82f6;
border-radius: 8px;
margin-bottom: 10px;
position: relative;
}
.tool-call:hover {
background: rgba(255, 255, 255, 0.1);
}
/* Hover info tooltip */
.hover-info {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: rgba(30, 41, 59, 0.95);
color: #f1f5f9;
padding: 12px;
border-radius: 8px;
width: 300px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
border: 1px solid rgba(100, 116, 139, 0.5);
font-size: 0.9rem;
pointer-events: none;
}
.hover-info:before {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: rgba(30, 41, 59, 0.95);
}
.timeline-item:hover .hover-info {
opacity: 1;
visibility: visible;
}
/* Adjust positioning for edge cases */
.timeline-item:first-child .hover-info {
transform: translateX(-50%);
left: 50%;
}
.timeline-item:last-child .hover-info {
transform: translateX(-50%);
left: 50%;
}
/* Ensure tooltip stays within viewport */
@media (max-width: 768px) {
.hover-info {
left: 0;
transform: none;
width: calc(100vw - 80px);
right: 20px;
}
.hover-info:before {
left: 20px;
transform: none;
}
}
.hover-info h4 {
font-weight: 600;
margin-bottom: 8px;
color: #60a5fa;
}
.hover-info p {
margin: 0 0 10px 0;
line-height: 1.4;
}
.hover-info .role {
font-style: italic;
color: #94a3b8;
font-size: 0.85rem;
margin-bottom: 8px;
}
.hover-info .function {
background: rgba(59, 130, 246, 0.2);
padding: 8px;
border-radius: 6px;
margin-top: 8px;
}
/* Adjust for top edge visibility */
.agent-timeline {
padding: 20px 10px 20px 40px;
position: relative;
}
.scenario-card {
transition: all 0.2s ease;
}
.scenario-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); }
100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
}
.form-control {
background: rgba(15, 23, 42, 0.5);
border: 1px solid rgba(148, 163, 184, 0.3);
border-radius: 12px;
padding: 0.75rem;
color: #f1f5f9;
width: 100%;
transition: all 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
.status-approved {
background: linear-gradient(90deg, #10b981, #34d399);
color: white;
}
.status-blocked {
background: linear-gradient(90deg, #ef4444, #f87171);
color: white;
}
.status-manual {
background: linear-gradient(90deg, #f59e0b, #fbbf24);
color: #1e293b;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="text-center mb-12">
<h1 class="text-4xl font-bold text-white mb-2">Multi-Agent Orchestration Demo</h1>
<p class="text-slate-300 max-w-3xl mx-auto">Simulating intelligent coordination between agents across different scenarios</p>
</header>
<!-- Main Content -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left Column - Controls -->
<div class="lg:col-span-1 space-y-6">
<!-- Scenario Selector -->
<div class="card p-6">
<h2 class="text-xl font-bold text-white mb-4">Scenario Selection</h2>
<div class="space-y-4">
<div>
<label class="form-label">Select Scenario</label>
<select id="scenarioSelector" class="form-control">
<option value="devops">DevOps Release Gate</option>
<option value="security">Security Alert Triage</option>
<option value="data">Data Pipeline Publish</option>
<option value="it">IT Onboarding (Helpdesk)</option>
</select>
</div>
<div class="flex items-center justify-between pt-2">
<div class="flex items-center">
<span class="mr-3 text-sm font-medium text-slate-300">Mode:</span>
<div class="toggle-container">
<input type="checkbox" id="modeToggle">
<span class="toggle-slider"></span>
</div>
<span class="ml-3 text-sm font-medium text-slate-300">Demo</span>
<span class="ml-1 text-sm font-medium text-slate-300">Live</span>
</div>
<button id="runButton" class="btn btn-primary">
<i class="fas fa-play btn-icon"></i> Run Orchestration
</button>
</div>
</div>
</div>
<!-- Dynamic Form -->
<div class="card p-6">
<h2 class="text-xl font-bold text-white mb-4">Scenario Inputs</h2>
<div id="dynamicForm" class="space-y-4">
<!-- Form will be populated dynamically -->
</div>
</div>
<!-- Final Decision -->
<div id="decisionCard" class="card p-6 hidden">
<h2 class="text-xl font-bold text-white mb-4">Final Decision</h2>
<div id="decisionContent" class="text-center">
<!-- Decision content will be populated dynamically -->
</div>
</div>
</div>
<!-- Right Column - Agent Timeline -->
<div class="lg:col-span-2 flex flex-col h-full">
<div class="card p-6 flex-grow flex flex-col timeline-container">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold text-white">Agent Orchestration Timeline</h2>
<div class="flex space-x-2">
<button id="clearTimeline" class="btn btn-secondary">
<i class="fas fa-trash btn-icon"></i> Clear
</button>
</div>
</div>
<div id="agentTimeline" class="agent-timeline flex-grow">
<!-- Timeline items will be populated dynamically -->
<div class="text-center py-10 text-slate-400">
<i class="fas fa-robot text-4xl mb-3"></i>
<p>No orchestration run yet. Select a scenario and click "Run Orchestration".</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Agent definitions with role descriptions
const agents = {
mastermind: {
name: "MasterMind",
color: "#3b82f6",
icon: "fas fa-brain",
role: "Orchestration coordinator that manages the workflow and makes final decisions"
},
devassist: {
name: "DevAssist",
color: "#10b981",
icon: "fas fa-code",
role: "Development expert that reviews code quality and technical implementation"
},
cyberguard: {
name: "CyberGuard",
color: "#ef4444",
icon: "fas fa-shield-alt",
role: "Security specialist that identifies risks and ensures compliance"
},
dataflow: {
name: "DataFlow",
color: "#8b5cf6",
icon: "fas fa-database",
role: "Data expert that validates data quality and pipeline integrity"
}
};
// Scenario definitions
const scenarios = {
devops: {
name: "DevOps Release Gate",
description: "Coordinate release approval with security and data checks",
formFields: [
{ id: "title", label: "PR Title", type: "text", placeholder: "Fix authentication bug" },
{ id: "diff", label: "Code Diff", type: "textarea", placeholder: "Paste code changes here..." },
{ id: "environment", label: "Environment", type: "select", options: ["staging", "production"] }
],
flow: ["mastermind", "devassist", "cyberguard", "dataflow", "mastermind"]
},
security: {
name: "Security Alert Triage",
description: "Automatically triage and respond to security alerts",
formFields: [
{ id: "alert", label: "Alert JSON", type: "textarea", placeholder: '{"type": "unusual_login", "source": "192.168.1.100"}' },
{ id: "severity", label: "Severity", type: "select", options: ["low", "medium", "high"] }
],
flow: ["mastermind", "cyberguard", "devassist", "mastermind"]
},
data: {
name: "Data Pipeline Publish",
description: "Validate and publish data pipelines with quality checks",
formFields: [
{ id: "dataset", label: "Dataset Name", type: "text", placeholder: "sales_data_q3_2023" },
{ id: "environment", label: "Environment", type: "select", options: ["staging", "production"] },
{ id: "notes", label: "Notes", type: "textarea", placeholder: "Additional information about this dataset..." }
],
flow: ["mastermind", "dataflow", "cyberguard", "mastermind"]
},
it: {
name: "IT Onboarding (Helpdesk)",
description: "Automate employee onboarding with access provisioning",
formFields: [
{ id: "name", label: "Employee Name", type: "text", placeholder: "John Smith" },
{ id: "department", label: "Department", type: "select", options: ["Engineering", "Marketing", "Finance", "HR", "Operations"] },
{ id: "start_date", label: "Start Date", type: "date" },
{ id: "ticket_id", label: "Ticket ID (Optional)", type: "text", placeholder: "INC-12345" }
],
flow: ["mastermind", "devassist", "cyberguard", "mastermind"]
}
};
// Tool definitions
const tools = {
// DevOps tools
"github.lint": { name: "GitHub Linter", category: "dev" },
"sast.scan": { name: "SAST Scanner", category: "security" },
"ci.build": { name: "CI Build", category: "dev" },
// Security tools
"siem.lookup": { name: "SIEM Lookup", category: "security" },
"threatintel.query": { name: "Threat Intel Query", category: "security" },
"ticket.update": { name: "Ticket Update", category: "operations" },
// Data tools
"dbt.test": { name: "DBT Test", category: "data" },
"airflow.dag_status": { name: "Airflow DAG Status", category: "data" },
"schema.registry.diff": { name: "Schema Registry Diff", category: "data" },
// IT tools
"okta.create_user": { name: "Okta Create User", category: "identity" },
"okta.add_group": { name: "Okta Add Group", category: "identity" },
"slack.invite": { name: "Slack Invite", category: "communication" },
"servicenow.fetch": { name: "ServiceNow Fetch", category: "operations" }
};
// DOM Elements
const scenarioSelector = document.getElementById('scenarioSelector');
const modeToggle = document.getElementById('modeToggle');
const runButton = document.getElementById('runButton');
const dynamicForm = document.getElementById('dynamicForm');
const agentTimeline = document.getElementById('agentTimeline');
const decisionCard = document.getElementById('decisionCard');
const decisionContent = document.getElementById('decisionContent');
const clearTimeline = document.getElementById('clearTimeline');
// Current state
let currentScenario = 'devops';
let isLiveMode = false;
let formData = {};
// Initialize the page
document.addEventListener('DOMContentLoaded', function() {
// Set up event listeners
scenarioSelector.addEventListener('change', updateScenario);
modeToggle.addEventListener('change', toggleMode);
runButton.addEventListener('click', runOrchestration);
clearTimeline.addEventListener('click', clearTimelineContent);
// Initialize form
updateScenario();
});
// Update form based on selected scenario
function updateScenario() {
currentScenario = scenarioSelector.value;
const scenario = scenarios[currentScenario];
// Clear existing form
dynamicForm.innerHTML = '';
// Create form fields
scenario.formFields.forEach(field => {
const fieldElement = document.createElement('div');
fieldElement.className = 'space-y-1';
const label = document.createElement('label');
label.className = 'block text-sm font-medium text-gray-700';
label.textContent = field.label;
fieldElement.appendChild(label);
if (field.type === 'select') {
const select = document.createElement('select');
select.id = field.id;
select.className = 'w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent';
field.options.forEach(option => {
const optionElement = document.createElement('option');
optionElement.value = option;
optionElement.textContent = option.charAt(0).toUpperCase() + option.slice(1);
select.appendChild(optionElement);
});
fieldElement.appendChild(select);
} else if (field.type === 'textarea') {
const textarea = document.createElement('textarea');
textarea.id = field.id;
textarea.className = 'w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent';
textarea.placeholder = field.placeholder || '';
textarea.rows = 3;
fieldElement.appendChild(textarea);
} else {
const input = document.createElement('input');
input.type = field.type;
input.id = field.id;
input.className = 'w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent';
input.placeholder = field.placeholder || '';
if (field.type === 'date') {
const today = new Date();
input.value = today.toISOString().split('T')[0];
}
fieldElement.appendChild(input);
}
dynamicForm.appendChild(fieldElement);
});
}
// Toggle between Demo and Live mode
function toggleMode() {
isLiveMode = modeToggle.checked;
runButton.innerHTML = isLiveMode ?
'<i class="fas fa-bolt mr-2"></i> Run Live Orchestration' :
'<i class="fas fa-play mr-2"></i> Run Orchestration';
// In a real implementation, we would check for API key here
if (isLiveMode) {
alert("Live mode requires an API key. This demo only supports deterministic mode.");
modeToggle.checked = false;
isLiveMode = false;
runButton.innerHTML = '<i class="fas fa-play mr-2"></i> Run Orchestration';
}
}
// Clear timeline content
function clearTimelineContent() {
agentTimeline.innerHTML = `
<div class="text-center py-10 text-gray-500">
<i class="fas fa-robot text-4xl mb-3"></i>
<p>No orchestration run yet. Select a scenario and click "Run Orchestration".</p>
</div>
`;
decisionCard.classList.add('hidden');
}
// Run the orchestration
function runOrchestration() {
// Collect form data
formData = {};
const scenario = scenarios[currentScenario];
scenario.formFields.forEach(field => {
const element = document.getElementById(field.id);
if (element) {
formData[field.id] = element.value;
}
});
// Clear timeline
agentTimeline.innerHTML = '';
decisionCard.classList.add('hidden');
// Start orchestration
simulateOrchestration();
}
// Simulate the orchestration process
async function simulateOrchestration() {
const scenario = scenarios[currentScenario];
const flow = scenario.flow;
// Add initial message
addTimelineItem(agents.mastermind, "Starting orchestration for " + scenario.name, []);
// Process each step in the flow
for (let i = 0; i < flow.length; i++) {
const agentKey = flow[i];
const agent = agents[agentKey];
// Add thinking message
addTimelineItem(agent, `Analyzing request...`, []);
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, 800 + Math.random() * 700));
// Process agent action
const result = processAgentAction(agentKey, i);
// Add result to timeline
addTimelineItem(agent, result.message, result.toolCalls);
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, 600 + Math.random() * 500));
}
// Show final decision
showFinalDecision();
}
// Process agent action based on scenario and agent
function processAgentAction(agentKey, stepIndex) {
const scenario = scenarios[currentScenario];
let message = "";
let toolCalls = [];
switch (currentScenario) {
case 'devops':
switch (agentKey) {
case 'mastermind':
if (stepIndex === 0) {
message = "Evaluating release request for: " + (formData.title || "Untitled PR");
toolCalls = [
{ tool: "github.lint", params: { repo: "my-app", branch: "feature-branch" }, result: "ok" }
];
} else {
message = "Finalizing release decision";
}
break;
case 'devassist':
const hasSecurityRisk = formData.diff && (formData.diff.includes("eval(") || formData.diff.includes("raw user input"));
message = hasSecurityRisk ?
"Security risk detected in code changes" :
"Code review completed successfully";
toolCalls = [
{ tool: "sast.scan", params: { target: "src/", ruleset: "default" }, result: hasSecurityRisk ? "warn" : "ok" }
];
break;
case 'cyberguard':
const requiresApproval = formData.diff && (formData.diff.includes("eval(") || formData.diff.includes("raw user input"));
message = requiresApproval ?
"Manual approval required due to security policy SEC-12" :
"Security checks passed";
toolCalls = [
{ tool: "siem.lookup", params: { query: "suspicious_activity", timeframe: "24h" }, result: "ok" }
];
break;
case 'dataflow':
const env = formData.environment || "staging";
message = env === "production" ?
"Production deployment requires additional validation" :
"Staging environment ready for deployment";
toolCalls = [
{ tool: "airflow.dag_status", params: { dag_id: "deployment_pipeline" }, result: "ok" }
];
break;
}
break;
case 'security':
switch (agentKey) {
case 'mastermind':
if (stepIndex === 0) {
message = "Analyzing security alert with severity: " + (formData.severity || "unknown");
toolCalls = [
{ tool: "siem.lookup", params: { alert_id: "ALERT-001" }, result: "ok" }
];
} else {
message = "Alert triage completed";
}
break;
case 'cyberguard':
const severity = formData.severity || "low";
const requiresManual = severity === "high" || (formData.alert && formData.alert.includes("public_s3"));
message = requiresManual ?
"High severity alert requires manual review" :
"Alert classified and prioritized";
toolCalls = [
{ tool: "threatintel.query", params: { ip: "192.168.1.100" }, result: "warn" }
];
break;
case 'devassist':
message = "Runbook executed for alert response";
toolCalls = [
{ tool: "ticket.update", params: { ticket_id: "INC-12345", status: "in_progress" }, result: "ok" }
];
break;
}
break;
case 'data':
switch (agentKey) {
case 'mastermind':
if (stepIndex === 0) {
message = "Processing dataset: " + (formData.dataset || "Unnamed dataset");
toolCalls = [
{ tool: "schema.registry.diff", params: { dataset: formData.dataset }, result: "ok" }
];
} else {
message = "Dataset validation completed";
}
break;
case 'dataflow':
const dataset = formData.dataset || "";
const env = formData.environment || "staging";
const hasSales = dataset.includes("sales");
const hasPii = dataset.includes("pii");
if (hasSales) {
message = "Dataset contains sales data - late partition detected";
} else if (hasPii && env === "production") {
message = "PII detected in production dataset - privacy policy review required";
} else {
message = "Dataset quality checks passed";
}
toolCalls = [
{ tool: "dbt.test", params: { model: "sales_model" }, result: hasSales ? "warn" : "ok" }
];
break;
case 'cyberguard':
const hasPiiData = (formData.dataset || "").includes("pii");
const environment = formData.environment || "staging";
message = hasPiiData && environment === "production" ?
"PII policy validation required" :
"Data privacy checks passed";
toolCalls = [
{ tool: "siem.lookup", params: { query: "data_access", timeframe: "1h" }, result: "ok" }
];
break;
}
break;
case 'it':
switch (agentKey) {
case 'mastermind':
if (stepIndex === 0) {
message = "Initiating onboarding for: " + (formData.name || "New Employee");
toolCalls = [
{ tool: "servicenow.fetch", params: { ticket_id: formData.ticket_id || "TICKET-001" }, result: "ok" }
];
} else {
message = "Onboarding process completed";
}
break;
case 'devassist':
const department = formData.department || "";
const startDate = formData.start_date || "";
const isToday = new Date(startDate).toDateString() === new Date().toDateString();
const isWeekend = new Date(startDate).getDay() === 0 || new Date(startDate).getDay() === 6;
if (isToday || isWeekend) {
message = "Scheduling adjustment needed for start date";
} else {
message = "Onboarding plan generated successfully";
}
toolCalls = [
{ tool: "okta.create_user", params: { username: "john.smith" }, result: "ok" }
];
break;
case 'cyberguard':
const dept = formData.department || "";
message = dept === "Finance" ?
"SOX compliance review required for Finance department" :
"Access provisioning validated";
toolCalls = [
{ tool: "okta.add_group", params: { user: "john.smith", group: "engineering" }, result: dept === "Finance" ? "warn" : "ok" }
];
break;
}
break;
}
return { message, toolCalls };
}
// Add item to timeline with hover info
function addTimelineItem(agent, message, toolCalls) {
const timestamp = new Date().toLocaleTimeString();
const timelineItem = document.createElement('div');
timelineItem.className = 'timeline-item';
const avatar = document.createElement('div');
avatar.className = 'avatar';
avatar.style.backgroundColor = agent.color;
avatar.innerHTML = `<i class="${agent.icon}"></i>`;
const content = document.createElement('div');
content.className = 'bg-white p-4 rounded-lg shadow-sm';
const header = document.createElement('div');
header.className = 'flex justify-between items-start';
const agentInfo = document.createElement('div');
agentInfo.innerHTML = `
<div class="font-bold text-gray-800">${agent.name}</div>
<div class="text-xs text-gray-500">${timestamp}</div>
`;
header.appendChild(agentInfo);
const messageDiv = document.createElement('div');
messageDiv.className = 'mt-2 text-gray-700';
messageDiv.textContent = message;
content.appendChild(header);
content.appendChild(messageDiv);
// Add hover info tooltip
const hoverInfo = document.createElement('div');
hoverInfo.className = 'hover-info';
hoverInfo.innerHTML = `
<h4>${agent.name}</h4>
<div class="role">${agent.role}</div>
<p><strong>Current Action:</strong> ${getAgentActionDescription(agent, message)}</p>
<div class="function">
<strong>Agent Function:</strong> ${getAgentFunctionDescription(agent, currentScenario)}
</div>
`;
timelineItem.appendChild(hoverInfo);
// Add tool calls if any
if (toolCalls && toolCalls.length > 0) {
const toolSection = document.createElement('div');
toolSection.className = 'mt-3';
const toolHeader = document.createElement('div');
toolHeader.className = 'flex items-center text-sm font-medium text-gray-600 cursor-pointer tool-header';
toolHeader.innerHTML = `
<i class="fas fa-tools mr-2"></i>
<span>Tool Calls (${toolCalls.length})</span>
<i class="fas fa-chevron-down ml-auto transition-transform"></i>
`;
const toolContent = document.createElement('div');
toolContent.className = 'collapsible-content mt-2 space-y-2';
toolCalls.forEach(toolCall => {
const toolDiv = document.createElement('div');
toolDiv.className = 'tool-call p-3 rounded-lg';
const toolResultClass = toolCall.result === 'ok' ? 'text-green-600' :
toolCall.result === 'warn' ? 'text-yellow-600' : 'text-red-600';
toolDiv.innerHTML = `
<div class="font-medium">${tools[toolCall.tool].name}</div>
<div class="text-sm text-gray-600 mt-1">
<span class="font-medium">Params:</span>
<span class="font-mono text-xs">${JSON.stringify(toolCall.params)}</span>
</div>
<div class="mt-1">
<span class="font-medium">Result:</span>
<span class="${toolResultClass}">${toolCall.result.toUpperCase()}</span>
</div>
`;
toolContent.appendChild(toolDiv);
});
toolSection.appendChild(toolHeader);
toolSection.appendChild(toolContent);
content.appendChild(toolSection);
// Add event listener for collapsible
toolHeader.addEventListener('click', function() {
this.querySelector('i:last-child').classList.toggle('fa-chevron-down');
this.querySelector('i:last-child').classList.toggle('fa-chevron-up');
toolContent.classList.toggle('active');
});
}
timelineItem.appendChild(avatar);
timelineItem.appendChild(content);
agentTimeline.appendChild(timelineItem);
// Scroll to bottom
agentTimeline.scrollTop = agentTimeline.scrollHeight;
}
// Get agent action description based on message
function getAgentActionDescription(agent, message) {
const descriptions = {
"Starting orchestration": "Initiating the multi-agent workflow process",
"Evaluating release request": "Reviewing the release details and context",
"Analyzing request": "Processing the incoming task requirements",
"Analyzing security alert": "Examining the security event details",
"Processing dataset": "Validating the data pipeline information",
"Initiating onboarding": "Beginning the employee onboarding process",
"Finalizing release decision": "Making the final approval decision",
"Alert triage completed": "Finishing the security alert analysis",
"Dataset validation completed": "Completing data quality checks",
"Onboarding process completed": "Finishing employee setup process"
};
// Check for specific patterns
if (message.includes("Code review completed")) {
return "Performing code quality assessment and security scanning";
}
if (message.includes("Security risk detected")) {
return "Identifying potential security vulnerabilities in code";
}
if (message.includes("Manual approval required")) {
return "Flagging the task for human review due to policy requirements";
}
if (message.includes("Security checks passed")) {
return "Confirming no security issues were found";
}
if (message.includes("Production deployment requires")) {
return "Identifying additional validation needed for production";
}
if (message.includes("Alert classified and prioritized")) {
return "Categorizing and prioritizing the security alert";
}
if (message.includes("Runbook executed")) {
return "Executing automated response procedures";
}
if (message.includes("Dataset quality checks passed")) {
return "Verifying data integrity and schema compliance";
}
if (message.includes("Data privacy checks passed")) {
return "Ensuring data handling complies with privacy policies";
}
if (message.includes("Onboarding plan generated")) {
return "Creating customized setup plan for new employee";
}
if (message.includes("Access provisioning validated")) {
return "Confirming appropriate system access permissions";
}
// Default to predefined descriptions
for (const [key, desc] of Object.entries(descriptions)) {
if (message.includes(key)) {
return desc;
}
}
return "Performing specialized analysis and evaluation";
}
// Get agent function description based on scenario
function getAgentFunctionDescription(agent, scenario) {
const functions = {
devops: {
mastermind: "Coordinates the release process, evaluates code changes, and makes final deployment decisions",
devassist: "Reviews code quality, performs static analysis, and identifies technical risks",
cyberguard: "Checks for security vulnerabilities and ensures compliance with security policies",
dataflow: "Validates data pipeline integrity and ensures proper environment deployment"
},
security: {
mastermind: "Manages the security alert workflow and determines response actions",
cyberguard: "Analyzes threat intelligence and classifies security events",
devassist: "Executes automated security response procedures and updates tickets"
},
data: {
mastermind: "Orchestrates data pipeline validation and publication process",
dataflow: "Performs data quality checks and validates schema compliance",
cyberguard: "Ensures data privacy policies are followed and access is controlled"
},
it: {
mastermind: "Manages employee onboarding workflow and final access approvals",
devassist: "Generates onboarding plans and validates system requirements",
cyberguard: "Ensures appropriate access provisioning and compliance checks"
}
};
return functions[scenario][agent.name.toLowerCase()] || "Performing specialized analysis";
}
// Show final decision
function showFinalDecision() {
let decision = "";
let status = "";
let needsApproval = false;
switch (currentScenario) {
case 'devops':
const hasSecurityRisk = formData.diff && (formData.diff.includes("eval(") || formData.diff.includes("raw user input"));
const env = formData.environment || "staging";
const dataFlowResult = env === "production" ? "amber" : "green";
if (hasSecurityRisk) {
decision = "Manual approval required due to security policy violations";
status = "manual";
needsApproval = true;
} else if (dataFlowResult === "red") {
decision = "Release blocked due to data validation failures";
status = "blocked";
} else {
decision = "Release approved for deployment";
status = "approved";
}
break;
case 'security':
const severity = formData.severity || "low";
const requiresManual = severity === "high" || (formData.alert && formData.alert.includes("public_s3"));
if (requiresManual) {
decision = "High severity alert requires manual triage";
status = "manual";
needsApproval = true;
} else {
decision = "Alert resolved automatically";
status = "approved";
}
break;
case 'data':
const dataset = formData.dataset || "";
const environment = formData.environment || "staging";
const hasSales = dataset.includes("sales");
const hasPii = dataset.includes("pii");
if (hasPii && environment === "production") {
decision = "Manual approval required for PII data in production";
status = "manual";
needsApproval = true;
} else if (hasSales) {
decision = "Dataset published with late partition note";
status = "approved";
} else {
decision = "Dataset published successfully";
status = "approved";
}
break;
case 'it':
const department = formData.department || "";
if (department === "Finance") {
decision = "Manual approval required for SOX compliance";
status = "manual";
needsApproval = true;
} else {
decision = "Onboarding completed successfully";
status = "approved";
}
break;
}
// Create decision card
let statusClass = "";
let statusIcon = "";
switch (status) {
case "approved":
statusClass = "status-approved";
statusIcon = "fas fa-check-circle";
break;
case "blocked":
statusClass = "status-blocked";
statusIcon = "fas fa-times-circle";
break;
case "manual":
statusClass = "status-manual";
statusIcon = "fas fa-exclamation-circle";
break;
}
decisionContent.innerHTML = `
<div class="decision-card p-6 ${statusClass}">
<div class="flex items-center justify-center mb-4">
<i class="${statusIcon} text-3xl mr-3"></i>
<h3 class="text-2xl font-bold">${status.charAt(0).toUpperCase() + status.slice(1)}</h3>
</div>
<p class="text-lg mb-6">${decision}</p>
${needsApproval ? `
<button id="approveButton" class="w-full btn btn-primary">
<i class="fas fa-thumbs-up btn-icon"></i> Approve Anyway
</button>
` : ''}
</div>
`;
decisionCard.classList.remove('hidden');
// Add event listener for approve button if present
if (needsApproval) {
document.getElementById('approveButton').addEventListener('click', function() {
this.innerHTML = '<i class="fas fa-check mr-2"></i> Approved';
this.classList.add('bg-green-500', 'hover:bg-green-600');
this.classList.remove('bg-primary', 'hover:bg-blue-700');
this.disabled = true;
// Add audit log
addTimelineItem(agents.mastermind, "Manual approval granted by user", [
{ tool: "audit.log", params: { action: "manual_approval", user: "admin" }, result: "ok" }
]);
});
}
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=molliexx99/maias" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>