diff --git a/otel-collector.yaml b/otel-collector.yaml
deleted file mode 100644
index 19b3769..0000000
--- a/otel-collector.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-receivers:
- otlp:
- protocols:
- grpc:
- endpoint: 0.0.0.0:4317
-
-processors:
- batch:
- timeout: 1s
- send_batch_size: 50
-
-exporters:
- otlphttp/dashboard:
- endpoint: http://dashboard:3000
- encoding: json
- tls:
- insecure: true
-
-service:
- pipelines:
- traces:
- receivers: [otlp]
- processors: [batch]
- exporters: [otlphttp/dashboard]
-
- telemetry:
- logs:
- level: info
diff --git a/public/index.html b/public/index.html
index 6a82bc7..c71207f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -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;
@@ -543,7 +522,6 @@
Dashboard Status:
CONNECTING
-
@@ -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;
@@ -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') {
@@ -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
@@ -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 = {
@@ -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
// ============================================================
diff --git a/server.js b/server.js
index 7b17ecd..d8f68d3 100644
--- a/server.js
+++ b/server.js
@@ -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, {});
}
@@ -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: {} });
@@ -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) {
@@ -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);
diff --git a/translate.js b/translate.js
index e11a9da..0864dc0 100644
--- a/translate.js
+++ b/translate.js
@@ -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 ─────────────────────────────────────
@@ -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 };