diff --git a/packages/stats/app/src/component/model-compare-detail.tsx b/packages/stats/app/src/component/model-compare-detail.tsx
index 4966d5d453..fa82ea4952 100644
--- a/packages/stats/app/src/component/model-compare-detail.tsx
+++ b/packages/stats/app/src/component/model-compare-detail.tsx
@@ -24,6 +24,8 @@ import {
findModelCatalogEntry,
formatCatalogLabName,
getModelCatalog,
+ isKnownCatalogLab,
+ isProviderlessLab,
type ModelCatalog,
type ModelCatalogEntry,
} from "../routes/model-catalog"
@@ -71,7 +73,7 @@ const comparisonModelLimit = 6
type ComparisonModel = {
name: string
lab: string
- labName: string
+ labName?: string
slug: string
catalog: ModelCatalogEntry | null
stats: StatsModelComparisonEntry | null
@@ -159,13 +161,19 @@ export default function ModelCompareDetailPage(props: ModelCompareDetailPageProp
let comparisonBodyScroll: HTMLDivElement | undefined
const models = createMemo(() =>
modelSelections().map((model, index) =>
- buildComparisonModel(model.lab, model.slug, model.catalog ?? null, stats()?.models[index] ?? null),
+ buildComparisonModel(
+ model.lab,
+ model.slug,
+ model.catalog ?? null,
+ stats()?.models[index] ?? null,
+ catalog()?.labs.map((lab) => lab.id) ?? [],
+ ),
),
)
const title = createMemo(() => `${models()[0].name} vs ${models()[1].name} - AI Model Comparison`)
const description = createMemo(
() =>
- `Compare ${models()[0].name} from ${models()[0].labName} and ${models()[1].name} from ${models()[1].labName} on key metrics including benchmarks, price, context length, usage, and model features.`,
+ `Compare ${comparisonModelLabel(models()[0])} and ${comparisonModelLabel(models()[1])} on key metrics including benchmarks, price, context length, usage, and model features.`,
)
const canonicalPath = createMemo(() => {
if (props.family) return canonicalFamilyComparisonPath(props.family.first, props.family.second)
@@ -206,7 +214,7 @@ export default function ModelCompareDetailPage(props: ModelCompareDetailPageProp
"@type": "SoftwareApplication",
name: model.name,
applicationCategory: "AI model",
- provider: model.labName,
+ ...(model.labName ? { provider: model.labName } : {}),
})),
}),
)
@@ -459,7 +467,9 @@ function CompareDetailSelectButton(props: {
aria-expanded={props.expanded}
onClick={props.onOpen}
>
-
+
+ {(labName) => }
+
{props.model.name}
@@ -581,8 +591,7 @@ function CompareModelDetail(props: { model: ModelCatalogEntry }) {
- {props.model.description ??
- `${props.model.name} is an AI model from ${formatCatalogLabName(props.model.lab)}.`}
+ {props.model.description ?? `${props.model.name} is an AI model.`}
@@ -789,9 +798,11 @@ function LabLogo(props: { lab: string; label: string; size: "large" | "small" |
const iconId = () => getProviderIconId(props.lab)
return (
-
-
-
+
+
+
+
+
)
}
@@ -832,11 +843,13 @@ function buildComparisonModel(
modelParam: string,
catalog: ModelCatalogEntry | null,
stats: StatsModelComparisonEntry | null,
+ catalogLabs: readonly string[],
): ComparisonModel {
+ const lab = catalog?.lab ?? stats?.provider ?? catalogSlug(labParam)
return {
name: catalog?.name ?? stats?.model ?? formatParamName(modelParam),
- lab: catalog?.lab ?? stats?.provider ?? catalogSlug(labParam),
- labName: formatCatalogLabName(catalog?.lab ?? stats?.provider ?? labParam),
+ lab,
+ labName: isKnownCatalogLab(lab, catalogLabs) ? formatCatalogLabName(lab) : undefined,
slug: catalog?.slug ?? stats?.slug ?? catalogSlug(modelParam),
catalog,
stats,
@@ -877,7 +890,7 @@ function buildComparisonDetailSections(models: readonly ComparisonModel[]): Comp
rows: [
comparisonDetailRow(
"Author",
- models.map((model) => linkedTextCell(model.stats?.author ?? model.labName, labHref(model.lab))),
+ models.map(providerDetailCell),
),
comparisonDetailRow(
"Context length",
@@ -899,7 +912,7 @@ function buildComparisonDetailSections(models: readonly ComparisonModel[]): Comp
),
comparisonDetailRow(
"Providers",
- models.map((model) => linkedTextCell(model.labName, labHref(model.lab))),
+ models.map(providerDetailCell),
),
],
},
@@ -1013,6 +1026,15 @@ function comparisonRef(model: ComparisonModel): ComparisonModelRef {
}
}
+function comparisonModelLabel(model: ComparisonModel) {
+ return model.labName ? `${model.name} from ${model.labName}` : model.name
+}
+
+function providerDetailCell(model: ComparisonModel): ComparisonDetailCell {
+ if (!model.labName) return textCell("")
+ return linkedTextCell(model.stats?.author ?? model.labName ?? "", labHref(model.lab))
+}
+
function textCell(value: string): ComparisonDetailCell {
return { value }
}
diff --git a/packages/stats/app/src/routes/[lab]/[model].tsx b/packages/stats/app/src/routes/[lab]/[model].tsx
index 977660a83c..24cba8c083 100644
--- a/packages/stats/app/src/routes/[lab]/[model].tsx
+++ b/packages/stats/app/src/routes/[lab]/[model].tsx
@@ -17,7 +17,13 @@ import { LocaleLinks } from "../../component/locale-links"
import { useI18n } from "../../context/i18n"
import { useLanguage } from "../../context/language"
import { localizedUrl } from "../../lib/language"
-import { findModelCatalogEntry, formatCatalogLabName, loadModelCatalog, type ModelCatalogEntry } from "../model-catalog"
+import {
+ findModelCatalogEntry,
+ formatCatalogLabName,
+ isKnownCatalogLab,
+ loadModelCatalog,
+ type ModelCatalogEntry,
+} from "../model-catalog"
import { SectionHeading } from "../section-heading"
import { runStatsEffect } from "../../stats-runtime"
import { setStatsPageCacheHeaders } from "../stats-cache"
@@ -96,7 +102,9 @@ export default function StatsModel() {
const modelName = createMemo(
() => catalogEntry()?.name ?? publicModelName(canonicalModel()) ?? i18n.t("model.fallback"),
)
- const labName = createMemo(() => formatCatalogLabName(catalogEntry()?.lab ?? stats()?.provider ?? labParam()))
+ const lab = createMemo(() => catalogEntry()?.lab ?? stats()?.provider ?? labParam())
+ const catalogLabs = createMemo(() => page()?.catalog.labs.map((item) => item.id) ?? [])
+ const labName = createMemo(() => (isKnownCatalogLab(lab(), catalogLabs()) ? formatCatalogLabName(lab()) : undefined))
const formerName = createMemo(() => formerModelName(canonicalModel()))
const searchModelName = createMemo(() => (formerName() ? `${modelName()} (formerly ${formerName()})` : modelName()))
const modelTitle = createMemo(() => i18n.t("model.title", { model: searchModelName() }))
@@ -185,9 +193,14 @@ export default function StatsModel() {
-
+
props.catalog?.lab ?? props.data?.provider ?? props.labName
+ const labId = () => props.catalog?.lab ?? props.data?.provider
+ const hasLab = () => props.labName !== undefined
const modelName = () => props.catalog?.name ?? props.data?.model ?? i18n.t("model.fallback")
const weights = () => props.catalog?.weights[0]
const labs = () => props.catalogData?.labs ?? []
@@ -281,35 +295,31 @@ function ModelHero(props: {
Data
- /
- 0}
- fallback={
-
- {props.labName}
-
-
- }
- >
- ({
- href: language.route(`${import.meta.env.BASE_URL}${lab.id}`),
- label: lab.name,
- value: lab.id,
- }))}
- value={providerSlug(labId())}
- variant="model"
- />
+
+ /
+ 0}
+ fallback={{props.labName}}
+ >
+ ({
+ href: language.route(`${import.meta.env.BASE_URL}${lab.id}`),
+ label: lab.name,
+ value: lab.id,
+ }))}
+ value={providerSlug(labId() ?? "")}
+ variant="model"
+ />
+
/
0}
fallback={
-
- {modelName()}
-
+
+ {modelName()}
}
>
@@ -328,9 +338,11 @@ function ModelHero(props: {
-
-
-
+
+
+
+
+
{modelName()}
@@ -980,7 +992,7 @@ function GeoCountryList(props: {
)
}
-function ModelPeersSection(props: { data: StatsModelPageData | null }) {
+function ModelPeersSection(props: { data: StatsModelPageData | null; catalogLabs: readonly string[] }) {
const i18n = useI18n()
return (
@@ -993,7 +1005,7 @@ function ModelPeersSection(props: { data: StatsModelPageData | null }) {
>
- {(peer) => }
+ {(peer) => }
@@ -1011,23 +1023,29 @@ function MetricCard(props: { label: string; value: string; detail?: string; stat
)
}
-function PeerRow(props: { peer: ModelPeerEntry; active: boolean }) {
+function PeerRow(props: { peer: ModelPeerEntry; active: boolean; catalogLabs: readonly string[] }) {
const language = useLanguage()
+ const hasProvider = () => isKnownCatalogLab(props.peer.provider, props.catalogLabs)
return (
{String(props.peer.rank).padStart(2, "0")}
-
-
-
+
+
+
+
+
{props.peer.model}
- {props.peer.author}
+
+ {props.peer.author}
+
{formatTokens(props.peer.tokens)}
@@ -1050,6 +1068,7 @@ function ModelEmptyState(props: { title: string; description: string; compact?:
function modelComparisonPairs(
catalogModels: ModelCatalogOption[] | undefined,
+ catalogLabs: readonly string[],
catalogEntry: ModelCatalogEntry | null,
data: StatsModelPageData | null,
) {
@@ -1064,7 +1083,7 @@ function modelComparisonPairs(
name: peer.model,
lab: peer.provider,
slug: peer.slug,
- labName: peer.author,
+ labName: isKnownCatalogLab(peer.provider, catalogLabs) ? peer.author : undefined,
metric: `#${peer.rank} / ${formatTokens(peer.tokens)}`,
},
detail: "Usage peer",
@@ -1090,7 +1109,7 @@ function modelComparisonRef(
name: data.model,
lab: data.provider,
slug: data.slug,
- labName: data.author,
+ labName: undefined,
metric: `#${data.rank}`,
}
}
diff --git a/packages/stats/app/src/routes/compare-cards.tsx b/packages/stats/app/src/routes/compare-cards.tsx
index 24077bc3b9..50a0a38002 100644
--- a/packages/stats/app/src/routes/compare-cards.tsx
+++ b/packages/stats/app/src/routes/compare-cards.tsx
@@ -119,17 +119,24 @@ function ComparisonCardIcon() {
}
function ComparisonPanelCard(props: { pair: ComparisonPair }) {
+ const firstLabName = () => props.pair.first.labName
+ const secondLabName = () => props.pair.second.labName
+
return (
{props.pair.detail}
{props.pair.first.name} vs {props.pair.second.name}
-
- {props.pair.first.labName ?? formatCatalogLabName(props.pair.first.lab)}
-
- {props.pair.second.labName ?? formatCatalogLabName(props.pair.second.lab)}
-
+
+
+ {(name) => {name()}}
+
+
+
+ {(name) => {name()}}
+
+
{props.pair.first.metric ?? "Listed"} / {props.pair.second.metric ?? "Listed"}
@@ -143,14 +150,16 @@ function ComparisonLabLogo(props: { model: ComparisonModelRef }) {
const iconId = () => providerIconId(props.model.lab)
return (
-
-
-
+
+
+
+
+
)
}
diff --git a/packages/stats/app/src/routes/compare-radar.tsx b/packages/stats/app/src/routes/compare-radar.tsx
index d7403809ac..35ada12885 100644
--- a/packages/stats/app/src/routes/compare-radar.tsx
+++ b/packages/stats/app/src/routes/compare-radar.tsx
@@ -9,7 +9,7 @@ const toolUseBenchmarkPattern = /(terminal bench|claw eval|tau ?(?:bench|2|3))/
export type ComparisonRadarModel = {
name: string
- labName: string
+ labName?: string
catalog: ModelCatalogEntry | null
}
@@ -61,7 +61,7 @@ export function ComparisonRadar(props: ComparisonRadarProps) {
{model.name}
- {model.labName}
+ {(name) => {name()}}
)}
diff --git a/packages/stats/app/src/routes/index.css b/packages/stats/app/src/routes/index.css
index fc88132d25..e3e2de48e0 100644
--- a/packages/stats/app/src/routes/index.css
+++ b/packages/stats/app/src/routes/index.css
@@ -5320,6 +5320,10 @@ body {
text-decoration: none;
}
+[data-page="stats"] [data-component="model-peer-list"] a[data-providerless="true"] {
+ grid-template-columns: 32px minmax(0, 1fr) minmax(64px, auto);
+}
+
[data-page="stats"] [data-component="model-peer-list"] a:hover,
[data-page="stats"] [data-component="model-peer-list"] a[data-active="true"] {
border-color: var(--stats-text);
@@ -8483,6 +8487,10 @@ body {
gap: 12px;
}
+ [data-page="stats"] [data-component="model-peer-list"] a[data-providerless="true"] {
+ grid-template-columns: 28px minmax(0, 1fr) minmax(56px, auto);
+ }
+
[data-page="stats"] [data-slot="model-peer-rank"] {
width: 28px;
}
diff --git a/packages/stats/app/src/routes/index.tsx b/packages/stats/app/src/routes/index.tsx
index a24f803e1e..cb9cfe0e0a 100644
--- a/packages/stats/app/src/routes/index.tsx
+++ b/packages/stats/app/src/routes/index.tsx
@@ -21,7 +21,7 @@ import { LocaleLinks } from "../component/locale-links"
import { useI18n } from "../context/i18n"
import { useLanguage } from "../context/language"
import { localizedUrl } from "../lib/language"
-import { findModelCatalogEntry, loadModelCatalog, type ModelCatalog } from "./model-catalog"
+import { findModelCatalogEntry, isKnownCatalogLab, loadModelCatalog, type ModelCatalog } from "./model-catalog"
import { SectionHeading } from "./section-heading"
import { setStatsPageCacheHeaders } from "./stats-cache"
import { ComparisonCardsSection, uniqueComparisonPairs, type ComparisonModelRef } from "./compare-cards"
@@ -72,6 +72,7 @@ type StatsHomePageData = {
sessionCost: SessionCostEntry[]
retention: RetentionEntry[]
country: CountryEntry[]
+ catalogLabs: string[]
}
const countryNumericIds = new Map(
@@ -92,6 +93,7 @@ const getData = query(async () => {
sessionCost: stats.sessionCost.Go,
retention: stats.retention,
country: stats.country,
+ catalogLabs: catalog.labs.map((lab) => lab.id),
} satisfies StatsHomePageData
}, "getStatsHomeData")
@@ -147,7 +149,11 @@ export default function StatsHome() {
{(stats) => (
<>
-
+
@@ -156,7 +162,7 @@ export default function StatsHome() {
()
@@ -393,7 +399,12 @@ function TopModelsSection(props: { data: UsagePoint[]; leaderboard: LeaderboardE
}
>
-
+
)
@@ -806,6 +817,7 @@ function Leaderboard(props: {
data: LeaderboardEntry[]
activeModel: string | undefined
onActiveModelChange: (model: string | undefined) => void
+ catalogLabs: readonly string[]
}) {
const featured = createMemo(() => props.data.slice(0, 3))
const compact = createMemo(() => props.data.slice(3))
@@ -820,6 +832,7 @@ function Leaderboard(props: {
size="featured"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
+ catalogLabs={props.catalogLabs}
/>
)}
@@ -833,6 +846,7 @@ function Leaderboard(props: {
size="compact"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
+ catalogLabs={props.catalogLabs}
/>
)}
@@ -845,6 +859,7 @@ function Leaderboard(props: {
size="featured"
active={props.activeModel === entry.model}
onActiveModelChange={props.onActiveModelChange}
+ catalogLabs={props.catalogLabs}
/>
)}
@@ -858,9 +873,11 @@ function LeaderboardCard(props: {
size: "featured" | "compact"
active: boolean
onActiveModelChange: (model: string | undefined) => void
+ catalogLabs: readonly string[]
}) {
const i18n = useI18n()
const language = useLanguage()
+ const hasProvider = () => isKnownCatalogLab(props.entry.provider, props.catalogLabs)
return (
props.onActiveModelChange(props.entry.model)}
>
{String(props.entry.rank).padStart(2, "0")}
-
+
+
+
-
+
+
+
{props.entry.model}
{formatBillions(props.entry.tokens)}
- {props.entry.author}
+ }>
+ {props.entry.author}
+
{
const first = leaderboard[firstIndex]
const second = leaderboard[secondIndex]
- return first && second ? [{ first: leaderboardRef(first), second: leaderboardRef(second), detail }] : []
+ return first && second
+ ? [{ first: leaderboardRef(first, catalogLabs), second: leaderboardRef(second, catalogLabs), detail }]
+ : []
}),
)
}
-function leaderboardRef(entry: LeaderboardEntry): ComparisonModelRef {
+function leaderboardRef(entry: LeaderboardEntry, catalogLabs: readonly string[]): ComparisonModelRef {
return {
name: entry.model,
lab: entry.provider,
slug: modelSlug(entry.model),
- labName: entry.author,
+ labName: isKnownCatalogLab(entry.provider, catalogLabs) ? entry.author : undefined,
metric: `#${entry.rank} / ${formatBillions(entry.tokens)}`,
}
}
diff --git a/packages/stats/app/src/routes/model-catalog.ts b/packages/stats/app/src/routes/model-catalog.ts
index 44102ba3bd..c55af8594c 100644
--- a/packages/stats/app/src/routes/model-catalog.ts
+++ b/packages/stats/app/src/routes/model-catalog.ts
@@ -114,6 +114,16 @@ export function formatCatalogLabName(lab: string) {
return known[catalogSlug(lab)] ?? lab.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase())
}
+export function isProviderlessLab(lab: string | undefined) {
+ return !lab || catalogSlug(lab) === "unknown"
+}
+
+export function isKnownCatalogLab(lab: string | undefined, catalogLabs: readonly string[]) {
+ if (!lab || isProviderlessLab(lab)) return false
+ const key = catalogSlug(formatCatalogLabName(lab))
+ return catalogLabs.some((candidate) => catalogSlug(formatCatalogLabName(candidate)) === key)
+}
+
export function catalogSlug(value: string) {
return value
.trim()