@diegofornalha/crew-ai-tess-pareto
Version:
Integração TESS com Crew AI
484 lines (428 loc) • 14.3 kB
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>