Spaces:
Running
Running
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
<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> |