Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 0 additions & 6 deletions otel-collector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ receivers:
grpc:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove this file altogether, it's not used here

endpoint: 0.0.0.0:4317

processors:
batch:
timeout: 1s
send_batch_size: 50

exporters:
otlphttp/dashboard:
endpoint: http://dashboard:3000
Expand All @@ -20,7 +15,6 @@ service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp/dashboard]

telemetry:
Expand Down
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