<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>opensourcellmrouter — live requests</title>
<style>
:root {
color-scheme: dark light;
--bg: #0f1115;
--panel: #181b22;
--border: #2a2e38;
--text: #e6e6e6;
--muted: #9aa0ac;
--accent: #4f8cff;
--error: #ff5f5f;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--text);
}
header {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
background: var(--bg);
z-index: 1;
}
header h1 { font-size: 1rem; margin: 0; font-weight: 600; }
#status {
font-size: 0.8rem;
padding: 0.15rem 0.5rem;
border-radius: 999px;
border: 1px solid var(--border);
color: var(--muted);
}
#status.connected { color: #6ee7a0; border-color: #2d4a36; }
#status.disconnected { color: var(--error); border-color: #4a2d2d; }
#count { color: var(--muted); font-size: 0.8rem; margin-left: auto; }
main { padding: 0.75rem 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.entry {
border: 1px solid var(--border);
border-radius: 8px;
background: var(--panel);
padding: 0.6rem 0.8rem;
}
.entry.error { border-color: #4a2d2d; }
.row1 {
display: flex;
align-items: baseline;
gap: 0.5rem;
flex-wrap: wrap;
font-size: 0.85rem;
}
.time { color: var(--muted); font-variant-numeric: tabular-nums; }
.provider {
font-weight: 600;
color: var(--accent);
}
.model { color: var(--muted); }
.arrow { color: var(--muted); }
.duration { color: var(--muted); margin-left: auto; font-variant-numeric: tabular-nums; }
.pill {
display: inline-block;
font-size: 0.7rem;
padding: 0.1rem 0.45rem;
border-radius: 999px;
border: 1px solid var(--border);
color: var(--muted);
}
.pill.tag { border-color: #3a4a6b; color: #9cc0ff; }
.pill.plugin { border-color: #4a3a6b; color: #c39cff; }
.pill.response-tag { border-color: #6b3a3a; color: #ff9c9c; }
.body { margin-top: 0.4rem; display: grid; gap: 0.3rem; }
.prompt, .response, .error-msg {
font-size: 0.8rem;
white-space: pre-wrap;
word-break: break-word;
max-height: 4.5em;
overflow: hidden;
cursor: pointer;
position: relative;
}
.prompt.expanded, .response.expanded, .error-msg.expanded {
max-height: none;
}
.label { color: var(--muted); margin-right: 0.4em; }
.error-msg { color: var(--error); }
.usage { color: var(--muted); font-size: 0.75rem; }
.entry.inflight { border-color: #3a4a6b; opacity: 0.7; }
.inflight-spinner { color: #9cc0ff; font-size: 1.1em; }
.in-flight-badge {
font-size: 0.75rem;
padding: 0.1rem 0.4rem;
border-radius: 999px;
border: 1px solid #3a4a6b;
color: #9cc0ff;
}
</style>
</head>
<body>
<header>
<h1>opensourcellmrouter</h1>
<span id="status" class="disconnected">connecting…</span>
<span id="count"></span>
</header>
<main id="entries"></main>
<script>
const MAX_ENTRIES = 200;
const entriesEl = document.getElementById('entries');
const statusEl = document.getElementById('status');
const countEl = document.getElementById('count');
let count = 0;
const inFlight = new Map();
function fmtTime(ms) {
const d = new Date(ms);
return d.toLocaleTimeString();
}
function lastUserMessage(messages) {
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].role === 'user') return messages[i].content;
}
return messages.length ? messages[messages.length - 1].content : '';
}
function pill(text, cls) {
const span = document.createElement('span');
span.className = 'pill ' + cls;
span.textContent = text;
return span;
}
function toggleExpand(e) {
e.currentTarget.classList.toggle('expanded');
}
function renderEntry(entry) {
const el = document.createElement('div');
el.className = 'entry' + (entry.error ? ' error' : '');
const row1 = document.createElement('div');
row1.className = 'row1';
const time = document.createElement('span');
time.className = 'time';
time.textContent = fmtTime(entry.ts_ms);
row1.appendChild(time);
const provider = document.createElement('span');
provider.className = 'provider';
provider.textContent = entry.provider;
row1.appendChild(provider);
const model = document.createElement('span');
model.className = 'model';
if (entry.requested_model !== entry.sent_model) {
model.innerHTML = '';
model.append(entry.requested_model, ' ');
const arrow = document.createElement('span');
arrow.className = 'arrow';
arrow.textContent = '→';
model.appendChild(arrow);
model.append(' ' + entry.sent_model);
} else {
model.textContent = entry.sent_model;
}
row1.appendChild(model);
for (const tag of entry.tags || []) row1.appendChild(pill(tag, 'tag'));
for (const plugin of entry.plugins || []) row1.appendChild(pill(plugin, 'plugin'));
for (const tag of (entry.response && entry.response.tags) || []) row1.appendChild(pill(tag, 'response-tag'));
const duration = document.createElement('span');
duration.className = 'duration';
duration.textContent = entry.duration_ms + ' ms';
row1.appendChild(duration);
el.appendChild(row1);
const body = document.createElement('div');
body.className = 'body';
const prompt = document.createElement('div');
prompt.className = 'prompt';
prompt.addEventListener('click', toggleExpand);
const promptLabel = document.createElement('span');
promptLabel.className = 'label';
promptLabel.textContent = 'prompt:';
prompt.appendChild(promptLabel);
prompt.append(lastUserMessage(entry.messages || []));
body.appendChild(prompt);
if (entry.error) {
const err = document.createElement('div');
err.className = 'error-msg';
err.addEventListener('click', toggleExpand);
const errLabel = document.createElement('span');
errLabel.className = 'label';
errLabel.textContent = 'error:';
err.appendChild(errLabel);
err.append(entry.error);
body.appendChild(err);
} else if (entry.response) {
const resp = document.createElement('div');
resp.className = 'response';
resp.addEventListener('click', toggleExpand);
const respLabel = document.createElement('span');
respLabel.className = 'label';
respLabel.textContent = 'response:';
resp.appendChild(respLabel);
resp.append(entry.response.content || '');
body.appendChild(resp);
if (entry.response.usage) {
const usage = document.createElement('div');
usage.className = 'usage';
usage.textContent =
`${entry.response.usage.input_tokens} in / ${entry.response.usage.output_tokens} out tokens · ${entry.response.stop_reason}`;
body.appendChild(usage);
}
}
el.appendChild(body);
return el;
}
function renderStart(event) {
const el = document.createElement('div');
el.className = 'entry inflight';
const row1 = document.createElement('div');
row1.className = 'row1';
const time = document.createElement('span');
time.className = 'time';
time.textContent = fmtTime(event.ts_ms);
row1.appendChild(time);
const spinner = document.createElement('span');
spinner.className = 'inflight-spinner';
spinner.textContent = '⋯';
row1.appendChild(spinner);
const model = document.createElement('span');
model.className = 'model';
model.textContent = event.model;
row1.appendChild(model);
const badge = document.createElement('span');
badge.className = 'in-flight-badge';
badge.textContent = event.in_flight + ' in flight';
row1.appendChild(badge);
el.appendChild(row1);
inFlight.set(event.id, el);
entriesEl.insertBefore(el, entriesEl.firstChild);
}
function connect() {
const es = new EventSource('/dashboard/events' + location.search);
es.onopen = () => {
statusEl.textContent = 'connected';
statusEl.className = 'connected';
};
es.onerror = () => {
statusEl.textContent = 'disconnected — retrying…';
statusEl.className = 'disconnected';
};
es.onmessage = (ev) => {
let event;
try {
event = JSON.parse(ev.data);
} catch {
return;
}
if (event.type === 'start') {
renderStart(event);
return;
}
if (event.type === 'classified') {
const el = inFlight.get(event.id);
if (el && event.tags && event.tags.length) {
const row1 = el.querySelector('.row1');
for (const tag of event.tags) row1.appendChild(pill(tag, 'tag'));
}
return;
}
if (event.type === 'routed') {
const el = inFlight.get(event.id);
if (el) {
const providerEl = el.querySelector('.provider') || document.createElement('span');
providerEl.className = 'provider';
providerEl.textContent = event.provider;
const modelEl = el.querySelector('.model');
if (modelEl) modelEl.textContent = event.model;
const row1 = el.querySelector('.row1');
if (!el.querySelector('.provider')) {
const spinner = row1.querySelector('.inflight-spinner');
spinner.after(providerEl);
}
}
return;
}
if (event.type === 'complete') {
const placeholder = inFlight.get(event.id);
if (placeholder) {
placeholder.remove();
inFlight.delete(event.id);
}
count++;
countEl.textContent = count + ' request' + (count === 1 ? '' : 's');
entriesEl.insertBefore(renderEntry(event), entriesEl.firstChild);
while (entriesEl.children.length > MAX_ENTRIES) {
entriesEl.removeChild(entriesEl.lastChild);
}
}
};
}
connect();
</script>
</body>
</html>