import { html, nothing } from 'lit'; import { LightElement } from '../lib/base.js'; const PAGE_ID = 'llm-requests'; const PAGE_SIZE = 20; function formatDate(iso) { if (!iso) return '—'; return new Date(iso).toLocaleString(undefined, { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit', }); } function fmtTokens(n) { if (n == null) return '—'; if (n >= 1000) return (n / 1000).toFixed(1) + 'k'; return String(n); } function cacheHitPct(item) { if (item.cache_read_tokens == null || !item.input_tokens) return '—'; return (item.cache_read_tokens / item.input_tokens * 100).toFixed(0) + '%'; } function cacheTooltip(item) { const parts = []; if (item.cache_read_tokens != null) parts.push(`read: ${item.cache_read_tokens.toLocaleString()} tk`); if (item.cache_creation_tokens != null) parts.push(`write: ${item.cache_creation_tokens.toLocaleString()} tk`); return parts.length ? parts.join(' | ') : ''; } export class LlmRequestsPage extends LightElement { static properties = { _open: { state: true }, _items: { state: true }, _total: { state: true }, _page: { state: true }, _loading: { state: true }, _error: { state: true }, _agentId: { state: true }, _source: { state: true }, _from: { state: true }, _to: { state: true }, _applied: { state: true }, _detailId: { state: true }, }; constructor() { super(); this._open = false; this._items = []; this._total = 0; this._page = 1; this._loading = false; this._error = null; this._agentId = ''; this._source = ''; this._from = ''; this._to = ''; this._applied = {}; this._detailId = null; } connectedCallback() { super.connectedCallback(); window.addEventListener('llm-page-change', (e) => { this._open = e.detail.page === PAGE_ID; this.style.display = this._open ? 'flex' : 'none'; if (this._open) { const id = this._idFromHash(); this._detailId = id; if (id == null && this._items.length === 0) this._fetch(1); } }); } _idFromHash() { const parts = location.hash.replace('#', '').split('/'); if (parts[0] === PAGE_ID && parts[1]) { const n = Number(parts[1]); return isNaN(n) ? null : n; } return null; } _openDetail(id) { this._detailId = id; history.pushState({}, '', `#${PAGE_ID}/${id}`); } _back() { this._detailId = null; history.pushState({}, '', `#${PAGE_ID}`); if (this._items.length === 0) this._fetch(1); } // ── List fetching ──────────────────────────────────────────────────────────── async _fetch(page) { this._loading = true; this._error = null; const params = new URLSearchParams({ page }); if (this._agentId) params.set('agent_id', this._agentId); if (this._source) params.set('source', this._source); if (this._from) params.set('from', this._from); if (this._to) params.set('to', this._to); this._applied = { agentId: this._agentId, source: this._source, from: this._from, to: this._to }; try { const res = await fetch(`/api/dev/llm-requests?${params}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); this._items = data.items; this._total = data.total; this._page = data.page; } catch (e) { this._error = e.message; } finally { this._loading = false; } } _apply() { this._fetch(1); } _reset() { this._agentId = ''; this._source = ''; this._from = ''; this._to = ''; this._fetch(1); } get _totalPages() { return Math.max(1, Math.ceil(this._total / PAGE_SIZE)); } // ── Renders ────────────────────────────────────────────────────────────────── _renderFilters() { return html`
this._agentId = e.target.value} @keydown=${e => e.key === 'Enter' && this._apply()} />
this._source = e.target.value} @keydown=${e => e.key === 'Enter' && this._apply()} />
this._from = e.target.value} />
this._to = e.target.value} />
`; } _renderTable() { if (this._loading) return html`
Loading…
`; if (this._error) return html`
${this._error}
`; if (this._items.length === 0) return html`
No requests found.
`; return html`
${this._items.map(r => html` this._openDetail(r.id)}> ${r.error_text ? html` ` : nothing} `)}
Agent Source Model Date In tokens Out tokens Cache hit ms
${r.agent_id ?? '—'} ${r.source ?? '—'} ${r.model_name} ${formatDate(r.created_at)} ${fmtTokens(r.input_tokens)} ${fmtTokens(r.output_tokens)} ${cacheHitPct(r)} ${r.duration_ms}
${r.error_text}
`; } _renderPagination() { if (this._totalPages <= 1) return nothing; const pages = this._totalPages; const cur = this._page; return html`
Page ${cur} of ${pages} — ${this._total} results
`; } render() { if (this._detailId != null) { return html` this._back()}> `; } return html`

LLM Requests

${this._total} rows
${this._renderFilters()} ${this._renderTable()} ${this._renderPagination()}
`; } }