Agent-system1 / index.html
0xKirito's picture
Update index.html
9f14540 verified
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Agent System - Task Processing & Database Integration</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
color: white;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.system-status {
background: rgba(255,255,255,0.95);
border-radius: 15px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.status-card {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
padding: 15px;
border-radius: 10px;
text-align: center;
}
.status-card h3 {
font-size: 1.1rem;
margin-bottom: 5px;
}
.status-card .value {
font-size: 1.5rem;
font-weight: bold;
}
.main-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.panel {
background: rgba(255,255,255,0.95);
border-radius: 15px;
padding: 20px;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
}
.panel h2 {
color: #4a5568;
margin-bottom: 15px;
font-size: 1.3rem;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 8px;
}
.task-form {
display: grid;
gap: 15px;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-group label {
font-weight: 600;
margin-bottom: 5px;
color: #4a5568;
}
.form-group input,
.form-group select,
.form-group textarea {
padding: 10px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: #4299e1;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-success {
background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
color: #2d5a27;
}
.btn-danger {
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
color: #c53030;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
.task-list {
max-height: 400px;
overflow-y: auto;
}
.task-item {
background: #f7fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
transition: all 0.3s;
}
.task-item:hover {
background: #edf2f7;
transform: translateX(5px);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.task-id {
font-weight: 600;
color: #2d3748;
}
.task-status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
.status-queued { background: #fef5e7; color: #c05621; }
.status-processing { background: #e6fffa; color: #234e52; }
.status-completed { background: #f0fff4; color: #22543d; }
.status-failed { background: #fed7d7; color: #c53030; }
.agents-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px;
}
.agent-card {
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
border-radius: 10px;
padding: 15px;
text-align: center;
transition: transform 0.3s;
}
.agent-card:hover {
transform: scale(1.05);
}
.agent-name {
font-weight: 600;
margin-bottom: 5px;
color: #2d3748;
}
.agent-status {
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
display: inline-block;
margin-bottom: 10px;
}
.status-active { background: #c6f6d5; color: #22543d; }
.status-idle { background: #fed7e2; color: #97266d; }
.logs-container {
background: #1a202c;
color: #e2e8f0;
border-radius: 8px;
padding: 15px;
max-height: 300px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 12px;
line-height: 1.4;
}
.log-entry {
margin-bottom: 5px;
padding: 2px 0;
}
.log-timestamp {
color: #718096;
margin-right: 10px;
}
.log-level-info { color: #63b3ed; }
.log-level-success { color: #68d391; }
.log-level-warning { color: #f6ad55; }
.log-level-error { color: #fc8181; }
.database-panel {
grid-column: 1 / -1;
margin-top: 20px;
}
.db-actions {
display: flex;
gap: 10px;
margin-bottom: 15px;
flex-wrap: wrap;
}
.connection-status {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: #68d391;
animation: pulse 2s infinite;
}
.status-disconnected {
background: #fc8181;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.data-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.data-table th,
.data-table td {
border: 1px solid #e2e8f0;
padding: 8px 12px;
text-align: left;
}
.data-table th {
background: #f7fafc;
font-weight: 600;
color: #4a5568;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
border-radius: 15px;
padding: 30px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 10px;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #a0aec0;
}
.close-btn:hover {
color: #4a5568;
}
@media (max-width: 768px) {
.main-grid {
grid-template-columns: 1fr;
}
.status-grid {
grid-template-columns: repeat(2, 1fr);
}
.header h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 Advanced Agent System</h1>
<p>Task Processing Engine with Database Integration</p>
</div>
<!-- System Status -->
<div class="system-status">
<div class="status-grid">
<div class="status-card">
<h3>Active Agents</h3>
<div class="value" id="active-agents">0</div>
</div>
<div class="status-card">
<h3>Tasks Queued</h3>
<div class="value" id="queued-tasks">0</div>
</div>
<div class="status-card">
<h3>Processing</h3>
<div class="value" id="processing-tasks">0</div>
</div>
<div class="status-card">
<h3>Completed</h3>
<div class="value" id="completed-tasks">0</div>
</div>
<div class="status-card">
<h3>DB Records</h3>
<div class="value" id="db-records">0</div>
</div>
</div>
</div>
<!-- Main Grid -->
<div class="main-grid">
<!-- Task Creation Panel -->
<div class="panel">
<h2>📝 Create Task</h2>
<form class="task-form" id="task-form">
<div class="form-group">
<label for="task-type">Task Type</label>
<select id="task-type">
<option value="single">Single Task</option>
<option value="workflow">Workflow</option>
<option value="batch">Batch Processing</option>
<option value="scheduled">Scheduled Task</option>
<option value="monitoring">Monitoring</option>
</select>
</div>
<div class="form-group">
<label for="task-description">Description</label>
<textarea id="task-description" rows="3" placeholder="Describe what this task should do..."></textarea>
</div>
<div class="form-group">
<label for="task-priority">Priority</label>
<select id="task-priority">
<option value="low">Low</option>
<option value="normal" selected>Normal</option>
<option value="high">High</option>
<option value="urgent">Urgent</option>
</select>
</div>
<div class="form-group">
<label for="task-agent">Assign to Agent</label>
<select id="task-agent">
<option value="">Auto-assign</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Create Task</button>
</form>
</div>
<!-- Active Agents Panel -->
<div class="panel">
<h2>🤖 Active Agents</h2>
<div class="agents-grid" id="agents-container">
<!-- Agents will be populated here -->
</div>
<button class="btn btn-success" onclick="createAgent()">+ Add Agent</button>
</div>
</div>
<!-- Task Queue Panel -->
<div class="panel">
<h2>📋 Task Queue & Processing</h2>
<div class="task-list" id="task-list">
<!-- Tasks will be populated here -->
</div>
</div>
<!-- Database Integration Panel -->
<div class="panel database-panel">
<h2>🗄️ Database Integration</h2>
<div class="connection-status">
<div class="status-indicator" id="db-status"></div>
<span id="db-status-text">Connected to Local Storage</span>
</div>
<div class="db-actions">
<button class="btn btn-primary" onclick="initializeDatabase()">Initialize DB</button>
<button class="btn btn-success" onclick="exportData()">Export Data</button>
<button class="btn btn-danger" onclick="clearDatabase()">Clear Database</button>
<button class="btn btn-primary" onclick="showQueryInterface()">Query Interface</button>
</div>
<div id="db-content">
<table class="data-table" id="data-table">
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Status</th>
<th>Created</th>
<th>Updated</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="data-table-body">
</tbody>
</table>
</div>
</div>
<!-- System Logs -->
<div class="panel">
<h2>📊 System Logs</h2>
<div class="logs-container" id="logs-container">
<!-- Logs will be populated here -->
</div>
<button class="btn btn-danger" onclick="clearLogs()">Clear Logs</button>
</div>
</div>
<!-- Modal for Query Interface -->
<div class="modal" id="query-modal">
<div class="modal-content">
<div class="modal-header">
<h2>Database Query Interface</h2>
<button class="close-btn" onclick="closeModal()">&times;</button>
</div>
<div class="form-group">
<label for="query-input">SQL-like Query</label>
<textarea id="query-input" rows="4" placeholder="SELECT * FROM tasks WHERE status = 'completed'"></textarea>
</div>
<button class="btn btn-primary" onclick="executeQuery()">Execute Query</button>
<div id="query-results"></div>
</div>
</div>
<script>
// Database Manager Class
// Complete DatabaseManager Class for the Agent System
// Add this class BEFORE the TaskProcessingEngine class in your HTML file
class DatabaseManager {
constructor() {
this.connected = false;
this.tables = {
tasks: 'agent_tasks',
agents: 'agent_agents',
logs: 'agent_logs',
metrics: 'agent_metrics',
workflows: 'agent_workflows',
schedules: 'agent_schedules'
};
this.init();
}
init() {
try {
// Check if localStorage is available
if (typeof Storage !== "undefined") {
this.connected = true;
this.initializeTables();
console.log('✅ Database Manager initialized with localStorage');
} else {
console.error('❌ localStorage not supported');
this.connected = false;
}
} catch (error) {
console.error('❌ Database initialization failed:', error);
this.connected = false;
}
}
initializeTables() {
// Initialize empty arrays for each table if they don't exist
Object.values(this.tables).forEach(tableName => {
if (!localStorage.getItem(tableName)) {
localStorage.setItem(tableName, JSON.stringify([]));
}
});
}
generateId() {
// Generate unique ID using timestamp and random number
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// CREATE operations
async insert(tableName, data) {
try {
const records = this.getAll(tableName);
const newRecord = {
...data,
id: data.id || this.generateId(),
created_at: data.created_at || new Date().toISOString(),
updated_at: new Date().toISOString()
};
records.push(newRecord);
localStorage.setItem(tableName, JSON.stringify(records));
return newRecord;
} catch (error) {
console.error(`Insert failed for table ${tableName}:`, error);
throw error;
}
}
async insertMany(tableName, dataArray) {
try {
const records = this.getAll(tableName);
const newRecords = dataArray.map(data => ({
...data,
id: data.id || this.generateId(),
created_at: data.created_at || new Date().toISOString(),
updated_at: new Date().toISOString()
}));
records.push(...newRecords);
localStorage.setItem(tableName, JSON.stringify(records));
return newRecords;
} catch (error) {
console.error(`Batch insert failed for table ${tableName}:`, error);
throw error;
}
}
// READ operations
getAll(tableName) {
try {
const data = localStorage.getItem(tableName);
return data ? JSON.parse(data) : [];
} catch (error) {
console.error(`Get all failed for table ${tableName}:`, error);
return [];
}
}
getById(tableName, id) {
try {
const records = this.getAll(tableName);
return records.find(record => record.id === id);
} catch (error) {
console.error(`Get by ID failed for table ${tableName}:`, error);
return null;
}
}
query(tableName, filterFn) {
try {
const records = this.getAll(tableName);
return records.filter(filterFn);
} catch (error) {
console.error(`Query failed for table ${tableName}:`, error);
return [];
}
}
// Advanced query methods
where(tableName, conditions) {
try {
const records = this.getAll(tableName);
return records.filter(record => {
return Object.entries(conditions).every(([key, value]) => {
if (typeof value === 'object' && value !== null) {
// Handle operators like { $gt: 10 }, { $in: ['a', 'b'] }
if (value.$gt !== undefined) return record[key] > value.$gt;
if (value.$lt !== undefined) return record[key] < value.$lt;
if (value.$gte !== undefined) return record[key] >= value.$gte;
if (value.$lte !== undefined) return record[key] <= value.$lte;
if (value.$in !== undefined) return value.$in.includes(record[key]);
if (value.$nin !== undefined) return !value.$nin.includes(record[key]);
if (value.$ne !== undefined) return record[key] !== value.$ne;
}
return record[key] === value;
});
});
} catch (error) {
console.error(`Where query failed for table ${tableName}:`, error);
return [];
}
}
// UPDATE operations
async update(tableName, id, updateData) {
try {
const records = this.getAll(tableName);
const index = records.findIndex(record => record.id === id);
if (index !== -1) {
records[index] = {
...records[index],
...updateData,
updated_at: new Date().toISOString()
};
localStorage.setItem(tableName, JSON.stringify(records));
return records[index];
}
return null;
} catch (error) {
console.error(`Update failed for table ${tableName}:`, error);
throw error;
}
}
async updateWhere(tableName, conditions, updateData) {
try {
const records = this.getAll(tableName);
let updatedCount = 0;
const updatedRecords = records.map(record => {
const matches = Object.entries(conditions).every(([key, value]) => record[key] === value);
if (matches) {
updatedCount++;
return {
...record,
...updateData,
updated_at: new Date().toISOString()
};
}
return record;
});
localStorage.setItem(tableName, JSON.stringify(updatedRecords));
return updatedCount;
} catch (error) {
console.error(`Update where failed for table ${tableName}:`, error);
throw error;
}
}
// DELETE operations
async delete(tableName, id) {
try {
const records = this.getAll(tableName);
const filteredRecords = records.filter(record => record.id !== id);
if (filteredRecords.length !== records.length) {
localStorage.setItem(tableName, JSON.stringify(filteredRecords));
return true;
}
return false;
} catch (error) {
console.error(`Delete failed for table ${tableName}:`, error);
throw error;
}
}
async deleteWhere(tableName, conditions) {
try {
const records = this.getAll(tableName);
const filteredRecords = records.filter(record => {
return !Object.entries(conditions).every(([key, value]) => record[key] === value);
});
const deletedCount = records.length - filteredRecords.length;
localStorage.setItem(tableName, JSON.stringify(filteredRecords));
return deletedCount;
} catch (error) {
console.error(`Delete where failed for table ${tableName}:`, error);
throw error;
}
}
// UTILITY operations
async clearTable(tableName) {
try {
localStorage.setItem(tableName, JSON.stringify([]));
return true;
} catch (error) {
console.error(`Clear table failed for ${tableName}:`, error);
throw error;
}
}
async clearAllTables() {
try {
Object.values(this.tables).forEach(tableName => {
localStorage.setItem(tableName, JSON.stringify([]));
});
return true;
} catch (error) {
console.error('Clear all tables failed:', error);
throw error;
}
}
getTotalRecords() {
try {
let total = 0;
Object.values(this.tables).forEach(tableName => {
total += this.getAll(tableName).length;
});
return total;
} catch (error) {
console.error('Get total records failed:', error);
return 0;
}
}
getTableStats() {
try {
const stats = {};
Object.entries(this.tables).forEach(([key, tableName]) => {
stats[key] = {
tableName,
count: this.getAll(tableName).length
};
});
return stats;
} catch (error) {
console.error('Get table stats failed:', error);
return {};
}
}
// BACKUP and RESTORE operations
exportData() {
try {
const data = {};
Object.entries(this.tables).forEach(([key, tableName]) => {
data[key] = this.getAll(tableName);
});
const exportData = {
timestamp: new Date().toISOString(),
version: '1.0',
data: data
};
return JSON.stringify(exportData, null, 2);
} catch (error) {
console.error('Export data failed:', error);
throw error;
}
}
async importData(jsonData) {
try {
const importData = JSON.parse(jsonData);
if (!importData.data) {
throw new Error('Invalid import data format');
}
Object.entries(importData.data).forEach(([key, records]) => {
if (this.tables[key]) {
localStorage.setItem(this.tables[key], JSON.stringify(records));
}
});
return true;
} catch (error) {
console.error('Import data failed:', error);
throw error;
}
}
// SEARCH operations
search(tableName, searchTerm, fields = []) {
try {
const records = this.getAll(tableName);
const searchLower = searchTerm.toString().toLowerCase();
return records.filter(record => {
if (fields.length === 0) {
// Search all fields
return Object.values(record).some(value =>
value && value.toString().toLowerCase().includes(searchLower)
);
} else {
// Search specific fields
return fields.some(field =>
record[field] && record[field].toString().toLowerCase().includes(searchLower)
);
}
});
} catch (error) {
console.error(`Search failed for table ${tableName}:`, error);
return [];
}
}
// PAGINATION
paginate(tableName, page = 1, limit = 10, orderBy = 'created_at', order = 'desc') {
try {
const records = this.getAll(tableName);
// Sort records
const sortedRecords = records.sort((a, b) => {
const aVal = a[orderBy];
const bVal = b[orderBy];
if (order === 'desc') {
return aVal > bVal ? -1 : aVal < bVal ? 1 : 0;
} else {
return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
}
});
// Paginate
const startIndex = (page - 1) * limit;
const endIndex = startIndex + limit;
const paginatedRecords = sortedRecords.slice(startIndex, endIndex);
return {
data: paginatedRecords,
pagination: {
currentPage: page,
totalPages: Math.ceil(records.length / limit),
totalRecords: records.length,
hasNext: endIndex < records.length,
hasPrev: page > 1
}
};
} catch (error) {
console.error(`Pagination failed for table ${tableName}:`, error);
return { data: [], pagination: {} };
}
}
// VALIDATION
validateRecord(tableName, record, schema = null) {
// Basic validation - can be extended with more complex schemas
if (!record.id) {
record.id = this.generateId();
}
if (!record.created_at) {
record.created_at = new Date().toISOString();
}
record.updated_at = new Date().toISOString();
return record;
}
// CONNECTION status
isConnected() {
return this.connected;
}
getConnectionInfo() {
return {
connected: this.connected,
type: 'localStorage',
tables: Object.keys(this.tables).length,
totalRecords: this.getTotalRecords()
};
}
}
async processTask(task) {
const processor = this.processors.get(task.type) || this.processors.get('single');
return await processor.execute(task, this.agentSystem);
}
}
// Base Processor Class
class BaseProcessor {
async execute(task, agentSystem) {
// Simulate processing time
await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));
return {
processed: true,
result: `Task "${task.description}" completed successfully`,
timestamp: new Date().toISOString()
};
}
}
// Specific Processor Implementations
class SingleTaskProcessor extends BaseProcessor {
async execute(task, agentSystem) {
agentSystem.log(`Processing single task: ${task.id}`, 'info');
const result = await super.execute(task, agentSystem);
result.type = 'single_task';
return result;
}
}
class WorkflowProcessor extends BaseProcessor {
async execute(task, agentSystem) {
agentSystem.log(`Processing workflow: ${task.id}`, 'info');
const steps = ['Step 1: Initialize', 'Step 2: Process', 'Step 3: Finalize'];
const stepResults = [];
for (let i = 0; i < steps.length; i++) {
agentSystem.log(`Executing ${steps[i]}`, 'info');
await new Promise(resolve => setTimeout(resolve, 800));
stepResults.push(`${steps[i]} completed`);
}
return {
processed: true,
result: 'Workflow completed successfully',
steps: stepResults,
timestamp: new Date().toISOString()
};
}
}
class BatchProcessor extends BaseProcessor {
async execute(task, agentSystem) {
agentSystem.log(`Processing batch task: ${task.id}`, 'info');
const batchSize = 5;
const processed = [];
for (let i = 0; i < batchSize; i++) {
agentSystem.log(`Processing batch item ${i + 1}/${batchSize}`, 'info');
await new Promise(resolve => setTimeout(resolve, 500));
processed.push(`Item ${i + 1} processed`);
}
return {
processed: true,
result: `Batch processing completed - ${batchSize} items processed`,
items: processed,
timestamp: new Date().toISOString()
};
}
}
class ScheduledProcessor extends BaseProcessor {
async execute(task, agentSystem) {
agentSystem.log(`Processing scheduled task: ${task.id}`, 'info');
const result = await super.execute(task, agentSystem);
result.type = 'scheduled_task';
result.scheduledFor = task.parameters?.scheduledTime || 'immediate';
return result;
}
}
class MonitoringProcessor extends BaseProcessor {
async execute(task, agentSystem) {
agentSystem.log(`Processing monitoring task: ${task.id}`, 'info');
// Simulate monitoring checks
const checks = ['System Health', 'Database Status', 'Agent Status', 'Task Queue'];
const results = {};
for (const check of checks) {
await new Promise(resolve => setTimeout(resolve, 300));
results[check] = Math.random() > 0.8 ? 'Warning' : 'OK';
}
return {
processed: true,
result: 'Monitoring completed',
checks: results,
timestamp: new Date().toISOString()
};
}
}
// Enhanced Agent System with proper queue management
class EnhancedAgentSystem {
constructor() {
this.db = new DatabaseManager();
this.taskEngine = null;
this.agents = new Map();
this.tasks = [];
this.logs = [];
this.isInitialized = false;
this.processingQueue = false;
this.init();
}
async init() {
console.log('🚀 Initializing Enhanced Agent System...');
// Wait for database to be ready
await new Promise(resolve => {
const checkDb = () => {
if (this.db.connected) {
resolve();
} else {
setTimeout(checkDb, 100);
}
};
checkDb();
});
// FIXED: Initialize Task Processing Engine properly
this.taskEngine = new TaskProcessingEngine(this);
// Load existing data from database
await this.loadFromDatabase();
// Initialize default agents
this.createDefaultAgents();
// Start monitoring
this.startSystemMonitoring();
// Update UI
this.updateUI();
this.isInitialized = true;
this.log('System initialized successfully', 'success');
}
async loadFromDatabase() {
// Load tasks
const savedTasks = this.db.getAll(this.db.tables.tasks);
this.tasks = savedTasks.map(task => ({
...task,
createdAt: new Date(task.created_at),
updatedAt: new Date(task.updated_at)
}));
// Load agents
const savedAgents = this.db.getAll(this.db.tables.agents);
savedAgents.forEach(agent => {
this.agents.set(agent.id, {
...agent,
createdAt: new Date(agent.created_at),
status: 'idle' // Reset status on load
});
});
this.log(`Loaded ${this.tasks.length} tasks and ${this.agents.size} agents from database`, 'info');
}
createDefaultAgents() {
if (this.agents.size === 0) {
const defaultAgents = [
{ name: 'Task Manager', role: 'coordinator', capabilities: ['task_management', 'workflow'] },
{ name: 'Data Processor', role: 'worker', capabilities: ['data_processing', 'analysis'] },
{ name: 'Web Scraper', role: 'worker', capabilities: ['web_scraping', 'data_extraction'] },
{ name: 'Monitor Agent', role: 'observer', capabilities: ['monitoring', 'alerting'] }
];
defaultAgents.forEach(agentData => {
this.createAgent(agentData);
});
}
}
async createAgent(agentData) {
const agent = {
id: this.db.generateId(),
name: agentData.name,
role: agentData.role || 'worker',
capabilities: agentData.capabilities || [],
status: 'idle',
tasksCompleted: 0,
tasksInProgress: 0,
createdAt: new Date()
};
this.agents.set(agent.id, agent);
// Save to database
await this.db.insert(this.db.tables.agents, {
...agent,
createdAt: agent.createdAt.toISOString()
});
this.log(`Created agent: ${agent.name}`, 'success');
this.updateUI();
return agent;
}
async createTask(taskData) {
const task = {
id: this.db.generateId(),
type: taskData.type || 'single',
description: taskData.description,
priority: taskData.priority || 'normal',
assignedAgent: taskData.assignedAgent || null,
status: 'queued',
parameters: taskData.parameters || {},
dependencies: taskData.dependencies || [],
createdAt: new Date(),
retries: 0,
maxRetries: 3
};
this.tasks.push(task);
// Save to database
await this.db.insert(this.db.tables.tasks, {
...task,
createdAt: task.createdAt.toISOString()
});
this.log(`Created task: ${task.id} - ${task.description}`, 'info');
// FIXED: Process task if engine is ready and not already processing
if (this.taskEngine && !this.processingQueue) {
setTimeout(() => this.processNextTask(), 100);
}
this.updateUI();
return task;
// FIXED VERSION - Replace the processNextTask method with this corrected version
async processNextTask() {
if (this.processingQueue) return; // Prevent multiple simultaneous processing
const queuedTasks = this.tasks.filter(task => task.status === 'queued');
if (queuedTasks.length === 0) return;
this.processingQueue = true; // Set processing flag
// Sort by priority
const priorityOrder = { urgent: 4, high: 3, normal: 2, low: 1 };
queuedTasks.sort((a, b) => priorityOrder[b.priority] - priorityOrder[a.priority]);
const task = queuedTasks[0];
try {
// Update task status to processing
task.status = 'processing';
await this.db.update(this.db.tables.tasks, task.id, { status: 'processing' });
this.updateUI(); // Update UI immediately
// Process with task engine
const result = await this.taskEngine.processTask(task);
// Update task with results
task.status = 'completed';
task.result = result;
task.completedAt = new Date();
await this.db.update(this.db.tables.tasks, task.id, {
status: 'completed',
result: JSON.stringify(result),
completed_at: task.completedAt.toISOString()
});
this.log(`Task completed: ${task.id}`, 'success');
} catch (error) {
task.status = 'failed';
task.error = error.message;
await this.db.update(this.db.tables.tasks, task.id, {
status: 'failed',
error: error.message
});
this.log(`Task failed: ${task.id} - ${error.message}`, 'error');
}
this.processingQueue = false; // Reset processing flag
this.updateUI();
startSystemMonitoring() {
setInterval(() => {
this.updateSystemMetrics();
this.updateUI();
}, 5000);
}
updateSystemMetrics() {
const metrics = {
id: this.db.generateId(),
timestamp: new Date().toISOString(),
active_agents: Array.from(this.agents.values()).filter(a => a.status === 'active').length,
queued_tasks: this.tasks.filter(t => t.status === 'queued').length,
processing_tasks: this.tasks.filter(t => t.status === 'processing').length,
completed_tasks: this.tasks.filter(t => t.status === 'completed').length,
failed_tasks: this.tasks.filter(t => t.status === 'failed').length,
total_db_records: this.db.getTotalRecords()
};
// Save metrics to database (keep last 100 entries)
const savedMetrics = this.db.getAll(this.db.tables.metrics);
savedMetrics.push(metrics);
if (savedMetrics.length > 100) {
savedMetrics.splice(0, savedMetrics.length - 100);
}
localStorage.setItem(this.db.tables.metrics, JSON.stringify(savedMetrics));
}
log(message, level = 'info') {
const logEntry = {
id: this.db.generateId(),
timestamp: new Date(),
level: level,
message: message
};
this.logs.push(logEntry);
// Keep only last 100 logs in memory
if (this.logs.length > 100) {
this.logs.shift();
}
// Save to database
this.db.insert(this.db.tables.logs, {
...logEntry,
timestamp: logEntry.timestamp.toISOString()
});
console.log(`[${level.toUpperCase()}] ${message}`);
this.updateLogsUI();
}
updateUI() {
this.updateStatusCards();
this.updateAgentsDisplay();
this.updateTasksList();
this.updateDatabaseTable();
}
updateStatusCards() {
const activeAgents = Array.from(this.agents.values()).filter(a => a.status === 'active').length;
const queuedTasks = this.tasks.filter(t => t.status === 'queued').length;
const processingTasks = this.tasks.filter(t => t.status === 'processing').length;
const completedTasks = this.tasks.filter(t => t.status === 'completed').length;
const dbRecords = this.db.getTotalRecords();
document.getElementById('active-agents').textContent = activeAgents;
document.getElementById('queued-tasks').textContent = queuedTasks;
document.getElementById('processing-tasks').textContent = processingTasks;
document.getElementById('completed-tasks').textContent = completedTasks;
document.getElementById('db-records').textContent = dbRecords;
}
updateAgentsDisplay() {
const container = document.getElementById('agents-container');
container.innerHTML = '';
Array.from(this.agents.values()).forEach(agent => {
const agentCard = document.createElement('div');
agentCard.className = 'agent-card';
agentCard.innerHTML = `
<div class="agent-name">${agent.name}</div>
<div class="agent-status status-${agent.status}">${agent.status}</div>
<div style="font-size: 12px; color: #666;">
<div>Role: ${agent.role}</div>
<div>Tasks: ${agent.tasksCompleted || 0}</div>
</div>
<button class="btn btn-danger" onclick="agentSystem.deleteAgent('${agent.id}')" style="margin-top: 10px; padding: 5px 10px; font-size: 12px;">Remove</button>
`;
container.appendChild(agentCard);
});
// Update agent dropdown
const agentSelect = document.getElementById('task-agent');
agentSelect.innerHTML = '<option value="">Auto-assign</option>';
Array.from(this.agents.values()).forEach(agent => {
const option = document.createElement('option');
option.value = agent.id;
option.textContent = agent.name;
agentSelect.appendChild(option);
});
}
updateTasksList() {
const container = document.getElementById('task-list');
container.innerHTML = '';
// Sort tasks by creation date (newest first)
const sortedTasks = [...this.tasks].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
sortedTasks.slice(0, 20).forEach(task => { // Show only last 20 tasks
const taskItem = document.createElement('div');
taskItem.className = 'task-item';
const assignedAgent = task.assignedAgent ?
this.agents.get(task.assignedAgent)?.name || 'Unknown Agent' :
'Auto-assigned';
taskItem.innerHTML = `
<div class="task-header">
<span class="task-id">${task.id}</span>
<span class="task-status status-${task.status}">${task.status}</span>
</div>
<div style="margin-bottom: 8px;">
<strong>Type:</strong> ${task.type} |
<strong>Priority:</strong> ${task.priority} |
<strong>Agent:</strong> ${assignedAgent}
</div>
<div style="margin-bottom: 8px;">
<strong>Description:</strong> ${task.description}
</div>
<div style="font-size: 12px; color: #666;">
<div>Created: ${task.createdAt.toLocaleString()}</div>
${task.completedAt ? `<div>Completed: ${task.completedAt.toLocaleString()}</div>` : ''}
${task.error ? `<div style="color: #c53030;">Error: ${task.error}</div>` : ''}
</div>
<div style="margin-top: 10px;">
<button class="btn btn-danger" onclick="agentSystem.deleteTask('${task.id}')" style="padding: 5px 10px; font-size: 12px;">Delete</button>
${task.status === 'failed' ? `<button class="btn btn-primary" onclick="agentSystem.retryTask('${task.id}')" style="padding: 5px 10px; font-size: 12px; margin-left: 5px;">Retry</button>` : ''}
</div>
`;
container.appendChild(taskItem);
});
}
updateDatabaseTable() {
const tbody = document.getElementById('data-table-body');
tbody.innerHTML = '';
// Get recent records from all tables
const allRecords = [];
Object.entries(this.db.tables).forEach(([tableName, table]) => {
const records = this.db.getAll(table);
records.forEach(record => {
allRecords.push({
...record,
table: tableName
});
});
});
// Sort by creation date and take last 50
allRecords.sort((a, b) => new Date(b.created_at || b.timestamp) - new Date(a.created_at || a.timestamp));
allRecords.slice(0, 50).forEach(record => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${record.id}</td>
<td>${record.table}</td>
<td>${record.status || record.level || 'N/A'}</td>
<td>${new Date(record.created_at || record.timestamp).toLocaleString()}</td>
<td>${record.updated_at ? new Date(record.updated_at).toLocaleString() : 'N/A'}</td>
<td>
<button class="btn-danger" onclick="agentSystem.deleteRecord('${record.table}', '${record.id}')" style="padding: 3px 6px; font-size: 11px;">Delete</button>
</td>
`;
tbody.appendChild(row);
});
}
updateLogsUI() {
const container = document.getElementById('logs-container');
container.innerHTML = '';
this.logs.slice(-20).forEach(log => {
const logEntry = document.createElement('div');
logEntry.className = 'log-entry';
logEntry.innerHTML = `
<span class="log-timestamp">[${log.timestamp.toLocaleTimeString()}]</span>
<span class="log-level-${log.level}">[${log.level.toUpperCase()}]</span>
<span>${log.message}</span>
`;
container.appendChild(logEntry);
});
// Auto-scroll to bottom
container.scrollTop = container.scrollHeight;
}
async deleteAgent(agentId) {
if (confirm('Are you sure you want to delete this agent?')) {
this.agents.delete(agentId);
await this.db.delete(this.db.tables.agents, agentId);
this.log(`Deleted agent: ${agentId}`, 'warning');
this.updateUI();
}
}
async deleteTask(taskId) {
if (confirm('Are you sure you want to delete this task?')) {
this.tasks = this.tasks.filter(t => t.id !== taskId);
await this.db.delete(this.db.tables.tasks, taskId);
this.log(`Deleted task: ${taskId}`, 'warning');
this.updateUI();
}
}
async retryTask(taskId) {
const task = this.tasks.find(t => t.id === taskId);
if (task) {
task.status = 'queued';
task.retries = 0;
task.error = null;
await this.db.update(this.db.tables.tasks, taskId, {
status: 'queued',
error: null
});
this.log(`Retrying task: ${taskId}`, 'info');
this.updateUI();
setTimeout(() => this.processNextTask(), 100);
}
}
async deleteRecord(table, id) {
if (confirm('Are you sure you want to delete this record?')) {
await this.db.delete(table, id);
this.log(`Deleted record from ${table}: ${id}`, 'warning');
this.updateUI();
}
}
}
// Global system instance
let agentSystem;
// UI Event Handlers - FIXED: Prevent form submission redirect
document.addEventListener('DOMContentLoaded', function() {
// Initialize the system
agentSystem = new EnhancedAgentSystem();
// Task form submission
document.getElementById('task-form').addEventListener('submit', function(e) {
e.preventDefault(); // FIXED: This prevents the page redirect
const taskData = {
type: document.getElementById('task-type').value,
description: document.getElementById('task-description').value,
priority: document.getElementById('task-priority').value,
assignedAgent: document.getElementById('task-agent').value || null,
parameters: {}
};
if (taskData.description.trim()) {
agentSystem.createTask(taskData);
// Reset form
document.getElementById('task-form').reset();
} else {
alert('Please enter a task description');
// Global utility functions
function createAgent() {
const name = prompt('Enter agent name:');
if (name) {
const role = prompt('Enter agent role (worker/coordinator/observer):', 'worker');
const capabilities = prompt('Enter capabilities (comma-separated):', 'general').split(',').map(s => s.trim());
agentSystem.createAgent({
name: name,
role: role || 'worker',
capabilities: capabilities
});
}
}
function initializeDatabase() {
agentSystem.db.clearAll();
agentSystem.log('Database initialized', 'success');
agentSystem.updateUI();
}
function exportData() {
const data = {
tasks: agentSystem.tasks,
agents: Array.from(agentSystem.agents.values()),
logs: agentSystem.logs,
timestamp: new Date().toISOString()
};
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `agent_system_export_${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
agentSystem.log('Data exported successfully', 'success');
}
function clearDatabase() {
if (confirm('This will delete all data. Are you sure?')) {
agentSystem.db.clearAll();
agentSystem.tasks = [];
agentSystem.agents.clear();
agentSystem.logs = [];
agentSystem.log('Database cleared', 'warning');
agentSystem.updateUI();
}
}
function showQueryInterface() {
document.getElementById('query-modal').style.display = 'block';
}
function closeModal() {
document.getElementById('query-modal').style.display = 'none';
}
function executeQuery() {
const query = document.getElementById('query-input').value.trim();
const resultsDiv = document.getElementById('query-results');
if (!query) {
resultsDiv.innerHTML = '<p style="color: red;">Please enter a query</p>';
return;
}
// Simple query parser (basic SELECT functionality)
try {
let results = [];
const lowerQuery = query.toLowerCase();
if (lowerQuery.includes('from tasks')) {
results = agentSystem.tasks;
} else if (lowerQuery.includes('from agents')) {
results = Array.from(agentSystem.agents.values());
} else if (lowerQuery.includes('from logs')) {
results = agentSystem.logs;
} else {
throw new Error('Unsupported query. Use: SELECT * FROM tasks/agents/logs');
}
// Basic WHERE filtering
if (lowerQuery.includes('where')) {
const whereMatch = query.match(/where\s+(\w+)\s*=\s*'([^']+)'/i);
if (whereMatch) {
const [, field, value] = whereMatch;
results = results.filter(item => item[field] === value);
}
}
// Display results
if (results.length === 0) {
resultsDiv.innerHTML = '<p>No results found</p>';
} else {
const table = document.createElement('table');
table.className = 'data-table';
table.style.marginTop = '15px';
// Headers
const headers = Object.keys(results[0]);
const headerRow = table.insertRow();
headers.forEach(header => {
const th = document.createElement('th');
th.textContent = header;
headerRow.appendChild(th);
});
// Data rows
results.slice(0, 20).forEach(item => {
const row = table.insertRow();
headers.forEach(header => {
const cell = row.insertCell();
let value = item[header];
if (typeof value === 'object' && value !== null) {
value = JSON.stringify(value);
}
cell.textContent = value || 'N/A';
});
});
resultsDiv.innerHTML = '';
resultsDiv.appendChild(table);
}
agentSystem.log(`Query executed: ${query}`, 'info');
} catch (error) {
resultsDiv.innerHTML = `<p style="color: red;">Query Error: ${error.message}</p>`;
agentSystem.log(`Query failed: ${error.message}`, 'error');
}
}
function clearLogs() {
agentSystem.logs = [];
agentSystem.db.clear(agentSystem.db.tables.logs);
agentSystem.updateLogsUI();
agentSystem.log('Logs cleared', 'info');
}
}
});
});
</script>