UNPKG

@diegofornalha/crew-ai-tess-pareto

Version:
484 lines (428 loc) 14.3 kB
<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TESS-MCP WebSocket Client</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; color: #333; } .container { max-width: 1200px; margin: 0 auto; } header { background-color: #4A8CFF; color: white; padding: 15px; border-radius: 8px; margin-bottom: 20px; } h1 { margin: 0; font-size: 24px; } .card { background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); padding: 20px; margin-bottom: 20px; } .tools-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 15px; } .tool-card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px; transition: all 0.2s ease; } .tool-card:hover { box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); transform: translateY(-3px); } .tool-title { font-weight: bold; color: #4A8CFF; margin-top: 0; margin-bottom: 10px; } .tool-description { color: #666; font-size: 14px; margin-bottom: 15px; } .btn { background-color: #4A8CFF; color: white; border: none; padding: 8px 15px; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.2s ease; } .btn:hover { background-color: #3a7ae0; } .status { margin-top: 15px; padding: 10px; border-radius: 4px; } .status.connected { background-color: #e8f5e9; color: #2e7d32; } .status.disconnected { background-color: #ffebee; color: #c62828; } .logs { background-color: #333; color: #fff; padding: 15px; border-radius: 8px; font-family: monospace; height: 300px; overflow-y: auto; margin-bottom: 20px; } .log-entry { margin-bottom: 5px; line-height: 1.5; } .log-entry.success { color: #4caf50; } .log-entry.error { color: #f44336; } .execution-status { font-weight: bold; } .execution-status.completed { color: #4caf50; } .execution-status.failed, .execution-status.error { color: #f44336; } .execution-status.running { color: #2196f3; } pre { background-color: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto; font-size: 13px; } .test-panel { display: flex; gap: 20px; margin-bottom: 20px; } .test-panel select { flex: 1; padding: 8px; border-radius: 4px; border: 1px solid #ddd; } .test-form { margin-top: 15px; } .test-form .form-group { margin-bottom: 10px; } .test-form label { display: block; margin-bottom: 5px; font-weight: bold; } .test-form input, .test-form textarea, .test-form select { width: 100%; padding: 8px; border-radius: 4px; border: 1px solid #ddd; } </style> </head> <body> <div class="container"> <header> <h1>TESS-MCP WebSocket Client</h1> </header> <div class="card"> <h2>Conexão WebSocket</h2> <div id="connection-status" class="status disconnected">Desconectado</div> <button id="connect-btn" class="btn">Conectar</button> <button id="disconnect-btn" class="btn" style="display: none;">Desconectar</button> </div> <div class="card"> <h2>Ferramentas TESS Disponíveis</h2> <button id="list-tools-btn" class="btn">Listar Ferramentas</button> <div id="tools-container" class="tools-container" style="margin-top: 15px;"></div> </div> <div class="card"> <h2>Testar Ferramenta</h2> <div class="test-panel"> <select id="tool-select"> <option value="">Selecione uma ferramenta</option> </select> <button id="test-tool-btn" class="btn">Testar</button> </div> <div id="tool-form-container"></div> </div> <div class="card"> <h2>Logs</h2> <div id="logs" class="logs"></div> <button id="clear-logs-btn" class="btn">Limpar Logs</button> </div> </div> <script src="/socket.io/socket.io.js"></script> <script> // Elementos DOM const connectionStatus = document.getElementById('connection-status'); const connectBtn = document.getElementById('connect-btn'); const disconnectBtn = document.getElementById('disconnect-btn'); const listToolsBtn = document.getElementById('list-tools-btn'); const toolsContainer = document.getElementById('tools-container'); const toolSelect = document.getElementById('tool-select'); const testToolBtn = document.getElementById('test-tool-btn'); const toolFormContainer = document.getElementById('tool-form-container'); const logsElement = document.getElementById('logs'); const clearLogsBtn = document.getElementById('clear-logs-btn'); // Variáveis globais let socket; let tools = []; // Conectar ao WebSocket function connectWebSocket() { socket = io(); // Evento de conexão estabelecida socket.on('connect', () => { updateConnectionStatus(true); addLog('Conectado ao servidor WebSocket', 'success'); }); // Evento de desconexão socket.on('disconnect', () => { updateConnectionStatus(false); addLog('Desconectado do servidor WebSocket', 'error'); }); // Evento de erro socket.on('error', (data) => { addLog(`Erro: ${data.message}`, 'error'); }); // Evento de lista de ferramentas socket.on('tools_list', (data) => { tools = data.tools; displayTools(tools); populateToolSelect(tools); addLog('Lista de ferramentas recebida', 'success'); }); // Evento de resultado de ferramenta socket.on('tool_result', (data) => { if (data.isError) { addLog(`Erro ao executar ${data.name}: ${data.error}`, 'error'); } else { addLog(`Ferramenta ${data.name} executada com sucesso`, 'success'); addLog(`Resultado: ${JSON.stringify(data.result, null, 2)}`); } }); // Evento de atualização de execução socket.on('execution_update', (data) => { let statusClass = 'running'; if (['completed', 'failed', 'error'].includes(data.status)) { statusClass = data.status; } addLog(`Execução ${data.id} - Status: <span class="execution-status ${statusClass}">${data.status}</span>`); }); // Evento de conclusão de execução socket.on('execution_complete', (data) => { addLog(`Execução ${data.id} concluída com status: <span class="execution-status ${data.status}">${data.status}</span>`, 'success'); if (data.data && data.data.output) { addLog(`Saída: ${data.data.output}`); } }); // Evento de erro de execução socket.on('execution_error', (data) => { addLog(`Erro na execução ${data.id}: ${data.error}`, 'error'); }); } // Atualizar status de conexão function updateConnectionStatus(connected) { connectionStatus.textContent = connected ? 'Conectado' : 'Desconectado'; connectionStatus.className = `status ${connected ? 'connected' : 'disconnected'}`; connectBtn.style.display = connected ? 'none' : 'inline-block'; disconnectBtn.style.display = connected ? 'inline-block' : 'none'; // Habilitar ou desabilitar botões listToolsBtn.disabled = !connected; testToolBtn.disabled = !connected; } // Adicionar mensagem aos logs function addLog(message, type = '') { const logEntry = document.createElement('div'); logEntry.className = `log-entry ${type}`; logEntry.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}`; logsElement.appendChild(logEntry); logsElement.scrollTop = logsElement.scrollHeight; } // Exibir ferramentas na interface function displayTools(tools) { toolsContainer.innerHTML = ''; tools.forEach(tool => { const toolCard = document.createElement('div'); toolCard.className = 'tool-card'; const title = document.createElement('h3'); title.className = 'tool-title'; title.textContent = tool.name; const description = document.createElement('div'); description.className = 'tool-description'; description.textContent = tool.description; const parametersTitle = document.createElement('div'); parametersTitle.textContent = 'Parâmetros:'; parametersTitle.style.fontWeight = 'bold'; parametersTitle.style.marginBottom = '5px'; const parametersList = document.createElement('ul'); parametersList.style.fontSize = '13px'; parametersList.style.marginTop = '5px'; tool.parameters.forEach(param => { const paramItem = document.createElement('li'); paramItem.textContent = `${param.name}${param.required ? ' (obrigatório)' : ''}: ${param.description}`; parametersList.appendChild(paramItem); }); toolCard.appendChild(title); toolCard.appendChild(description); toolCard.appendChild(parametersTitle); toolCard.appendChild(parametersList); toolsContainer.appendChild(toolCard); }); } // Preencher select de ferramentas function populateToolSelect(tools) { toolSelect.innerHTML = '<option value="">Selecione uma ferramenta</option>'; tools.forEach(tool => { const option = document.createElement('option'); option.value = tool.name; option.textContent = tool.name; toolSelect.appendChild(option); }); } // Gerar formulário para testar ferramenta function generateToolForm(toolName) { const tool = tools.find(t => t.name === toolName); if (!tool) return; toolFormContainer.innerHTML = ''; const form = document.createElement('form'); form.className = 'test-form'; form.id = 'tool-test-form'; tool.parameters.forEach(param => { const formGroup = document.createElement('div'); formGroup.className = 'form-group'; const label = document.createElement('label'); label.textContent = `${param.name}${param.required ? ' *' : ''}: ${param.description}`; let input; if (param.type === 'textarea') { input = document.createElement('textarea'); } else if (param.type === 'select') { input = document.createElement('select'); if (param.options) { param.options.forEach(option => { const optionEl = document.createElement('option'); optionEl.value = option; optionEl.textContent = option; input.appendChild(optionEl); }); } } else { input = document.createElement('input'); input.type = param.type === 'number' ? 'number' : 'text'; } input.name = param.name; input.id = `param-${param.name}`; if (param.default !== undefined) { input.value = param.default; } input.required = param.required; formGroup.appendChild(label); formGroup.appendChild(input); form.appendChild(formGroup); }); const submitBtn = document.createElement('button'); submitBtn.type = 'submit'; submitBtn.className = 'btn'; submitBtn.textContent = 'Executar'; form.appendChild(submitBtn); form.addEventListener('submit', (e) => { e.preventDefault(); executeSelectedTool(tool); }); toolFormContainer.appendChild(form); } // Executar ferramenta selecionada function executeSelectedTool(tool) { const args = {}; tool.parameters.forEach(param => { const input = document.getElementById(`param-${param.name}`); if (input) { if (param.type === 'number') { args[param.name] = parseFloat(input.value); } else if (param.type === 'boolean') { args[param.name] = input.value === 'true'; } else if (param.type === 'array') { args[param.name] = input.value ? input.value.split(',').map(i => i.trim()) : undefined; } else { args[param.name] = input.value; } } }); addLog(`Executando ${tool.name} com parâmetros: ${JSON.stringify(args)}`); socket.emit('call_tool', { name: tool.name, arguments: args }); } // Event Listeners connectBtn.addEventListener('click', () => { connectWebSocket(); }); disconnectBtn.addEventListener('click', () => { if (socket) { socket.disconnect(); } }); listToolsBtn.addEventListener('click', () => { if (socket) { socket.emit('list_tools'); addLog('Solicitando lista de ferramentas...'); } }); toolSelect.addEventListener('change', () => { const selectedTool = toolSelect.value; if (selectedTool) { generateToolForm(selectedTool); } else { toolFormContainer.innerHTML = ''; } }); testToolBtn.addEventListener('click', () => { const selectedTool = toolSelect.value; if (selectedTool) { generateToolForm(selectedTool); } }); clearLogsBtn.addEventListener('click', () => { logsElement.innerHTML = ''; }); // Inicializar updateConnectionStatus(false); </script> </body> </html>