import { ExternalLink } from 'lucide-react'; import { EntityLink } from '@/components/ui/entity'; import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table'; import { Note } from '@/components/ui/section'; import { fmtDateTime, fmtAgo, fmtUsdPerM, num } from '@/lib/format'; import type { ChangeEvent } from '@/lib/types'; type PriceValue = { input_per_mtok?: unknown; output_per_mtok?: unknown } | null | undefined; function pv(v: unknown): { input: number | null; output: number | null } { const o = (v && typeof v === 'object' ? v : {}) as PriceValue; return { input: num(o?.input_per_mtok), output: num(o?.output_per_mtok) }; } function host(url: string): string { try { return new URL(url).hostname.replace(/^www\./, ''); } catch { return 'source'; } } /** Old → new price cell: strike-through old, bold new, direction sign. Amber = money. */ function Move({ from, to }: { from: number | null; to: number | null }) { if (from === null && to === null) return —; const dir = from !== null && to !== null ? (to < from ? '↓' : to > from ? '↑' : '=') : ''; return ( {fmtUsdPerM(from)} → {fmtUsdPerM(to)} {dir && dir !== '=' && {dir}} ); } /** PRICE_CHANGED events as a dense table: model · provider · input move · output move · when · source. */ export function PriceMovers({ movers }: { movers: ChangeEvent[] }) { const rows = movers.filter((e) => e.event_type === 'PRICE_CHANGED' || e.category === 'price'); return ( <> Model Provider Input / 1M Output / 1M Observed Source {rows.length === 0 && No price change recorded in this window. The first observation of a price is not a change.} {rows.map((e) => { const o = pv(e.old_value); const n = pv(e.new_value); const provider = typeof e.meta?.provider === 'string' ? e.meta.provider : null; return ( {e.entity ? : —} {e.entity?.organization && {e.entity.organization.name}} {provider ?? —} {fmtAgo(e.observed_at)} {e.source_url ? ( {host(e.source_url)} ) : ( — )} ); })} {rows.length > 0 && Movers are PRICE_CHANGED events emitted when a provider's published price for a model differs from the previous observation. Green arrow = cheaper, red = dearer.} ); }