Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions otel-collector.yaml

This file was deleted.

67 changes: 7 additions & 60 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,6 @@
margin-right: 2px;
}

.btn-reset {
padding: 2px 8px;
font-size: 10px;
font-family: var(--font-sans);
font-weight: 500;
color: var(--color-muted);
background: transparent;
border: 1px solid rgba(139, 148, 158, 0.35);
border-radius: 4px;
cursor: pointer;
text-transform: none;
letter-spacing: normal;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.btn-reset:hover {
color: var(--color-text);
background: rgba(139, 148, 158, 0.1);
border-color: rgba(139, 148, 158, 0.4);
}

.panel-content {
flex: 1;
overflow-y: auto;
Expand Down Expand Up @@ -543,7 +522,6 @@
<span class="status-label">Dashboard Status:</span>
<span class="connection-label connecting" id="connection-label">CONNECTING</span>
</div>
<button class="btn-reset" id="btn-reset-demo" title="Reset demo to initial state">Reset Demo</button>
</div>
</div>
<div class="panel" id="panel-registry">
Expand Down Expand Up @@ -649,13 +627,15 @@

switch (eventType) {
case 'agent.created':
return 'Agent ' + (attrs['agent.id'] || '') + ' provisioned';
return (attrs['user.id'] || '') + ' → ' + (attrs['agent.id'] || '');
case 'agent.terminated':
return 'Agent ' + (attrs['agent.id'] || '') + ' terminated';
case 'request.allowed':
return (attrs['http.host'] || '') + ' -- allowed';
case 'request.denied':
return (attrs['http.host'] || '') + ' -- denied' + (attrs['denial.reason'] ? ': ' + attrs['denial.reason'] : '');
case 'agent.prompted':
return (attrs['user.id'] || 'user') + ' → ' + (attrs['agent.id'] || 'agent');
default:
if (attrs['agent.id']) return eventType + ' for ' + attrs['agent.id'];
return eventType;
Expand Down Expand Up @@ -694,12 +674,6 @@
const attrs = event.attributes || {};
const agentId = attrs['agent.id'] || '';

// Demo reset — clear all local state
if (eventType === 'demo.reset') {
clearAllDashboardState();
return;
}

// User lifecycle. Event names are speculative until the backend
// settles its vocabulary; the handler shape stays the same.
if (eventType === 'user.created') {
Expand All @@ -711,12 +685,11 @@
if (userId) Topology.removeUserNode(userId);
}

// User actions — light up the user→platform edge.
if (eventType === 'agent.requested' || eventType === 'prompt.sent' || eventType === 'permission.change_requested' || eventType === 'termination.requested') {
// agent.prompted: user→platform then platform→agent sequentially
if (eventType === 'agent.prompted') {
const userId = attrs['user.id'] || '';
if (userId) {
Topology.highlightEdge(userId, Topology.EDGE_HIGHLIGHT_MS);
}
if (userId) Topology.highlightEdge(userId, Topology.EDGE_HIGHLIGHT_MS);
if (agentId) setTimeout(() => Topology.highlightEdge('platform-' + agentId, Topology.EDGE_HIGHLIGHT_MS), 400);
}

// Agent lifecycle. Light up the platform→agent edge: the platform is
Expand All @@ -731,11 +704,6 @@
Topology.removeAgentRuntimeNode(agentId);
}

// Prompt delivered: platform exec'd into the agent via the supervisor.
if (eventType === 'agent.prompted') {
if (agentId) Topology.highlightEdge('platform-' + agentId, Topology.EDGE_HIGHLIGHT_MS);
}

// Gateway decisions
if (eventType === 'auth.allowed' || eventType === 'request.allowed' || eventType === 'request.denied' || eventType === 'permission.checked') {
const decision = {
Expand Down Expand Up @@ -866,27 +834,6 @@
else startRegistryPolling();
});

// ============================================================
// Reset button
// ============================================================
document.getElementById('btn-reset-demo').addEventListener('click', async () => {
const btn = document.getElementById('btn-reset-demo');
btn.disabled = true;
btn.textContent = 'Resetting...';

try {
const res = await fetch('/api/reset', { method: 'POST' });
if (res.ok) {
clearAllDashboardState();
}
} catch (err) {
console.error('Reset failed:', err);
} finally {
btn.disabled = false;
btn.textContent = 'Reset Demo';
}
});

// ============================================================
// Init
// ============================================================
Expand Down
63 changes: 7 additions & 56 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,8 @@ const server = http.createServer(async (req, res) => {
attributes: body.attributes || {},
received_at: new Date().toISOString(),
};
if (ev.event_type === 'demo.reset') {
events = [];
} else {
events.push(ev);
if (events.length > MAX_EVENTS) events = events.slice(-MAX_EVENTS);
}
events.push(ev);
if (events.length > MAX_EVENTS) events = events.slice(-MAX_EVENTS);
broadcastEvent(ev);
return sendJson(res, 200, {});
}
Expand All @@ -138,12 +134,8 @@ const server = http.createServer(async (req, res) => {
const body = await parseBody(req);
for (const ev of translateOtlpLogs(body)) {
ev.received_at = new Date().toISOString();
if (ev.event_type === 'demo.reset') {
events = [];
} else {
events.push(ev);
if (events.length > MAX_EVENTS) events = events.slice(-MAX_EVENTS);
}
events.push(ev);
if (events.length > MAX_EVENTS) events = events.slice(-MAX_EVENTS);
broadcastEvent(ev);
}
return sendJson(res, 200, { partialSuccess: {} });
Expand Down Expand Up @@ -228,48 +220,6 @@ const server = http.createServer(async (req, res) => {
}
}

// POST /api/reset - proxy to demo-admin reset endpoint
if (pathName === '/api/reset' && method === 'POST') {
const adminHost = process.env.ADMIN_HOST || 'demo-admin';
const adminPort = process.env.ADMIN_PORT || '8080';
return new Promise((resolve) => {
let responded = false;
const proxyReq = http.request({
hostname: adminHost,
port: parseInt(adminPort),
path: '/api/reset',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
timeout: 30000,
}, (proxyRes) => {
let body = '';
proxyRes.on('data', chunk => { body += chunk; });
proxyRes.on('end', () => {
if (responded) return;
responded = true;
events = [];
res.writeHead(proxyRes.statusCode, { 'Content-Type': 'application/json' });
res.end(body);
resolve();
});
});
proxyReq.on('error', (err) => {
if (responded) return;
responded = true;
sendJson(res, 502, { error: 'Failed to reach demo-admin: ' + err.message });
resolve();
});
proxyReq.on('timeout', () => {
proxyReq.destroy();
if (responded) return;
responded = true;
sendJson(res, 504, { error: 'demo-admin request timed out' });
resolve();
});
proxyReq.end();
});
}

// Serve static files for everything else
serveStatic(req, res);
} catch (e) {
Expand All @@ -283,8 +233,9 @@ const wss = new WebSocketServer({ server, path: '/ws' });
wss.on('connection', (ws) => {
wsClients.add(ws);

// Send event history on connect
ws.send(JSON.stringify({ type: 'history', events }));
// Send event history on connect, sorted chronologically
const sortedEvents = [...events].sort((a, b) => (a.timestamp < b.timestamp ? -1 : a.timestamp > b.timestamp ? 1 : 0));
ws.send(JSON.stringify({ type: 'history', events: sortedEvents }));

ws.on('close', () => {
wsClients.delete(ws);
Expand Down
4 changes: 2 additions & 2 deletions translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function translateOtlpLogs(otlp) {
}
}
}
return out;
return out.sort((a, b) => (a.timestamp < b.timestamp ? -1 : a.timestamp > b.timestamp ? 1 : 0));
}

// ─── Jaeger trace export → flat events ─────────────────────────────────────
Expand Down Expand Up @@ -198,7 +198,7 @@ function translateOtlpTraces(payload) {
}
}
}
return out;
return out.sort((a, b) => (a.timestamp < b.timestamp ? -1 : a.timestamp > b.timestamp ? 1 : 0));
}

module.exports = { translateOtlpLogs, translateJaegerTraces, translateOtlpTraces };
Loading