Tarefas executáveis, broadcast global para agendamentos e dashboard persistente

- Tarefas agora são templates executáveis com botão play e seleção de agente
- Dropdown de tarefas salvas no modal de execução para reutilização rápida
- Broadcast global no manager para execuções agendadas via cron aparecerem no terminal
- Dashboard atividade recente agora consulta executionsStore persistente
- Suporte a exibição de pipelines e agentes na atividade recente
This commit is contained in:
Frederico Castro
2026-02-26 02:14:47 -03:00
parent 4b6c876f36
commit 22a3ce9262
8 changed files with 126 additions and 13 deletions

View File

@@ -15,6 +15,16 @@ const DEFAULT_CONFIG = {
const MAX_RECENT = 200;
const recentExecBuffer = [];
let globalBroadcast = null;
export function setGlobalBroadcast(fn) {
globalBroadcast = fn;
}
function getWsCallback(wsCallback) {
return wsCallback || globalBroadcast || null;
}
let dailyExecutionCount = 0;
let dailyCountDate = new Date().toDateString();
@@ -100,6 +110,7 @@ export function executeTask(agentId, task, instructions, wsCallback) {
if (!agent) throw new Error(`Agente ${agentId} não encontrado`);
if (agent.status !== 'active') throw new Error(`Agente ${agentId} está inativo`);
const cb = getWsCallback(wsCallback);
const taskText = typeof task === 'string' ? task : task.description;
const startedAt = new Date().toISOString();
@@ -127,13 +138,13 @@ export function executeTask(agentId, task, instructions, wsCallback) {
{ description: task, instructions },
{
onData: (parsed, execId) => {
if (wsCallback) wsCallback({ type: 'execution_output', executionId: execId, agentId, data: parsed });
if (cb) cb({ type: 'execution_output', executionId: execId, agentId, data: parsed });
},
onError: (err, execId) => {
const endedAt = new Date().toISOString();
updateExecutionRecord(agentId, execId, { status: 'error', error: err.message, endedAt });
executionsStore.update(historyRecord.id, { status: 'error', error: err.message, endedAt });
if (wsCallback) wsCallback({ type: 'execution_error', executionId: execId, agentId, data: { error: err.message } });
if (cb) cb({ type: 'execution_error', executionId: execId, agentId, data: { error: err.message } });
},
onComplete: (result, execId) => {
const endedAt = new Date().toISOString();
@@ -144,7 +155,7 @@ export function executeTask(agentId, task, instructions, wsCallback) {
exitCode: result.exitCode,
endedAt,
});
if (wsCallback) wsCallback({ type: 'execution_complete', executionId: execId, agentId, data: result });
if (cb) cb({ type: 'execution_complete', executionId: execId, agentId, data: result });
},
}
);
@@ -205,7 +216,7 @@ export function scheduleTask(agentId, taskDescription, cronExpression, wsCallbac
schedulesStore.save(items);
scheduler.schedule(scheduleId, cronExpression, () => {
executeTask(agentId, taskDescription, null, wsCallback);
executeTask(agentId, taskDescription, null, null);
}, false);
return { scheduleId, agentId, agentName: agent.agent_name, taskDescription, cronExpression };
@@ -223,7 +234,7 @@ export function updateScheduleTask(scheduleId, data, wsCallback) {
const cronExpression = data.cronExpression || stored.cronExpression;
scheduler.updateSchedule(scheduleId, cronExpression, () => {
executeTask(agentId, taskDescription, null, wsCallback);
executeTask(agentId, taskDescription, null, null);
});
schedulesStore.update(scheduleId, { agentId, agentName: agent.agent_name, taskDescription, cronExpression });
@@ -266,10 +277,10 @@ export function importAgent(data) {
});
}
export function restoreSchedules(wsCallback) {
export function restoreSchedules() {
scheduler.restoreSchedules((agentId, taskDescription) => {
try {
executeTask(agentId, taskDescription, null, wsCallback);
executeTask(agentId, taskDescription, null, null);
} catch (err) {
console.log(`[manager] Erro ao executar tarefa agendada: ${err.message}`);
}

View File

@@ -436,7 +436,9 @@ router.get('/executions/active', (req, res) => {
router.get('/executions/recent', (req, res) => {
try {
const limit = parseInt(req.query.limit) || 20;
res.json(manager.getRecentExecutions(limit));
const items = executionsStore.getAll();
items.sort((a, b) => new Date(b.startedAt) - new Date(a.startedAt));
res.json(items.slice(0, limit));
} catch (err) {
res.status(500).json({ error: err.message });
}