Forked from OpenCode v1.17.4 with multi-agent system: - 5 agents: aircoding, scheduler, worker, architect, reviewer - Deterministic DAG scheduling engine (coordinator_tick) - Tool whitelists as hard enforcement - AirCoding validation plugin - System prompt injection for routing - V1 requirements: C4 docs, ADR, AGENTS.md, debug-log.md - Design documents in docs/
877 lines
32 KiB
TypeScript
877 lines
32 KiB
TypeScript
import { Effect } from "effect"
|
|
import { DatabaseError } from "../database"
|
|
import { GeoStatRepo, type GeoStatMetric } from "./geo"
|
|
import { ModelStatRepo, type ModelStatMetric } from "./model"
|
|
import { ProviderStatRepo, type ProviderStatMetric } from "./provider"
|
|
|
|
export type UsageProduct = "All Users" | "Zen" | "Go" | "Enterprise"
|
|
export type TokenProduct = "Zen" | "Go" | "Enterprise"
|
|
export type UsageRange = "1D" | "1W" | "2W" | "1M" | "2M" | "3M" | "YTD" | "ALL"
|
|
export type UsagePoint = { date: string; segments: { model: string; value: number }[] }
|
|
export type MarketDay = { date: string; total: number; authors: { author: string; share: number; tokens: number }[] }
|
|
export type LeaderboardEntry = {
|
|
model: string
|
|
provider: string
|
|
author: string
|
|
tokens: number
|
|
change: number | null
|
|
rank: number
|
|
}
|
|
export type TokenCostEntry = { model: string; total: number; input: number; output: number; cached: number }
|
|
export type CacheRatioEntry = { model: string; ratio: number; cached: number; uncached: number; total: number }
|
|
export type SessionCostEntry = { model: string; cost: number; tokens: number }
|
|
export type CountryEntry = { country: string; continent: string; tokens: number; share: number; rank: number }
|
|
export type ModelUsagePoint = { date: string; tokens: number; sessions: number; cost: number }
|
|
export type ModelMixEntry = { label: string; tokens: number; share: number }
|
|
export type ModelProductEntry = { product: string; tokens: number; sessions: number; share: number }
|
|
export type ModelPeerEntry = {
|
|
model: string
|
|
provider: string
|
|
author: string
|
|
rank: number
|
|
tokens: number
|
|
share: number
|
|
slug: string
|
|
}
|
|
export type LabUsageModelEntry = {
|
|
model: string
|
|
provider: string
|
|
author: string
|
|
tokens: number
|
|
share: number
|
|
slug: string
|
|
}
|
|
export type StatsModelData = {
|
|
updatedAt: string | null
|
|
model: string
|
|
slug: string
|
|
provider: string
|
|
author: string
|
|
rank: number
|
|
previousRank: number | null
|
|
totalModels: number
|
|
tokenShare: number
|
|
tokenChange: number
|
|
totals: {
|
|
sessions: number
|
|
tokens: number
|
|
cost: number
|
|
tokensPerSession: number
|
|
costPerSession: number
|
|
costPerMillion: number
|
|
cacheRatio: number
|
|
}
|
|
usage: ModelUsagePoint[]
|
|
tokenMix: ModelMixEntry[]
|
|
productMix: ModelProductEntry[]
|
|
country: Record<UsageRange, CountryEntry[]>
|
|
peers: ModelPeerEntry[]
|
|
}
|
|
export type StatsLabData = {
|
|
updatedAt: string | null
|
|
provider: string
|
|
author: string
|
|
tokenShare: number
|
|
tokenChange: number
|
|
totals: {
|
|
sessions: number
|
|
tokens: number
|
|
models: number
|
|
}
|
|
usage: ModelUsagePoint[]
|
|
models: LabUsageModelEntry[]
|
|
}
|
|
export type StatsHomeData = {
|
|
updatedAt: string | null
|
|
usage: Record<UsageProduct, Record<UsageRange, UsagePoint[]>>
|
|
leaderboard: Record<UsageProduct, Record<UsageRange, LeaderboardEntry[]>>
|
|
market: Record<UsageRange, MarketDay[]>
|
|
tokenCost: Record<TokenProduct, TokenCostEntry[]>
|
|
cacheRatio: Record<TokenProduct, CacheRatioEntry[]>
|
|
sessionCost: Record<TokenProduct, SessionCostEntry[]>
|
|
country: Record<UsageRange, CountryEntry[]>
|
|
}
|
|
|
|
const DAY_MS = 86_400_000
|
|
const TOKEN_SCALE = 1_000_000
|
|
const DOLLARS_PER_MICROCENT = 1 / 100_000_000
|
|
const METRIC_MODEL_LIMIT = 10
|
|
const LEADERBOARD_CHANGE_MIN_MULTIPLE = 10
|
|
const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"] as const
|
|
|
|
type StatMetricRow = Omit<ModelStatMetric, "updatedAt"> & {
|
|
periodStart: number
|
|
updatedAt: number
|
|
}
|
|
type ProviderMetricRow = Omit<ProviderStatMetric, "updatedAt"> & {
|
|
periodStart: number
|
|
updatedAt: number
|
|
}
|
|
type GeoMetricRow = Omit<GeoStatMetric, "updatedAt"> & {
|
|
periodStart: number
|
|
updatedAt: number
|
|
}
|
|
|
|
type DateWindow = { start: number; end: number; previousStart: number; previousEnd: number }
|
|
type Bucket = { start: number; end: number; label: string }
|
|
type ModelAggregate = {
|
|
model: string
|
|
provider: string
|
|
sessions: number
|
|
inputTokens: number
|
|
outputTokens: number
|
|
reasoningTokens: number
|
|
cacheReadTokens: number
|
|
totalTokens: number
|
|
inputCostMicrocents: number
|
|
outputCostMicrocents: number
|
|
totalCostMicrocents: number
|
|
}
|
|
|
|
export const getStatsHomeData: () => Effect.Effect<
|
|
StatsHomeData,
|
|
DatabaseError,
|
|
ModelStatRepo | ProviderStatRepo | GeoStatRepo
|
|
> = Effect.fn("StatsHome.getData")(function* () {
|
|
const modelStats = yield* ModelStatRepo
|
|
const providerStats = yield* ProviderStatRepo
|
|
const geoStats = yield* GeoStatRepo
|
|
const [modelRows, providerRows, geoRows] = yield* Effect.all(
|
|
[modelStats.listDaily(), providerStats.listDaily(), geoStats.listDaily()],
|
|
{ concurrency: "unbounded" },
|
|
)
|
|
return buildStatsHomeData(modelRows, providerRows, geoRows)
|
|
})
|
|
|
|
export const getStatsModelData: (
|
|
model: string,
|
|
provider?: string,
|
|
) => Effect.Effect<StatsModelData | null, DatabaseError, ModelStatRepo | GeoStatRepo> = Effect.fn("StatsModel.getData")(
|
|
function* (model, provider) {
|
|
const modelStats = yield* ModelStatRepo
|
|
const geoStats = yield* GeoStatRepo
|
|
const modelRows = yield* modelStats.listDaily()
|
|
const normalized = modelRows.flatMap(normalizeStatRow)
|
|
const resolvedModel = resolveModelName(model, normalized, provider)
|
|
if (!resolvedModel) return null
|
|
return buildStatsModelData(
|
|
resolvedModel,
|
|
modelRows,
|
|
yield* geoStats.listDaily({
|
|
model: resolvedModel,
|
|
provider: resolveModelProvider(resolvedModel, normalized, provider),
|
|
}),
|
|
provider,
|
|
)
|
|
},
|
|
)
|
|
|
|
export const getStatsLabData: (provider: string) => Effect.Effect<StatsLabData | null, DatabaseError, ModelStatRepo> =
|
|
Effect.fn("StatsLab.getData")(function* (provider) {
|
|
const modelStats = yield* ModelStatRepo
|
|
return buildStatsLabData(provider, yield* modelStats.listDaily())
|
|
})
|
|
|
|
function buildStatsHomeData(
|
|
modelRows: ModelStatMetric[],
|
|
providerRows: ProviderStatMetric[],
|
|
geoRows: GeoStatMetric[],
|
|
): StatsHomeData {
|
|
const normalized = modelRows.flatMap(normalizeStatRow)
|
|
const providers = providerRows.flatMap(normalizeProviderRow)
|
|
const geo = geoRows.flatMap(normalizeGeoRow)
|
|
const periods = [...normalized, ...providers, ...geo]
|
|
if (periods.length === 0) return emptyStatsHomeData()
|
|
|
|
const earliest = Math.min(...periods.map((row) => row.periodStart))
|
|
const latest = Math.max(...periods.map((row) => row.periodStart))
|
|
const latestUpdate = Math.max(...periods.map((row) => row.updatedAt))
|
|
|
|
return {
|
|
updatedAt: new Date(latestUpdate).toISOString(),
|
|
usage: createUsageProductRecord((product) =>
|
|
createRangeRecord((range) => buildUsagePoints(normalized, product, range, getWindow(range, earliest, latest))),
|
|
),
|
|
leaderboard: createUsageProductRecord((product) =>
|
|
createRangeRecord((range) => buildLeaderboard(normalized, product, getWindow(range, earliest, latest))),
|
|
),
|
|
market: createRangeRecord((range) => buildMarketShare(providers, "Go", range, getWindow(range, earliest, latest))),
|
|
tokenCost: createTokenProductRecord((product) =>
|
|
buildTokenCost(normalized, product, getWindow("1W", earliest, latest)),
|
|
),
|
|
cacheRatio: createTokenProductRecord((product) =>
|
|
buildCacheRatio(normalized, product, getWindow("1W", earliest, latest)),
|
|
),
|
|
sessionCost: createTokenProductRecord((product) =>
|
|
buildSessionCost(normalized, product, getWindow("1W", earliest, latest)),
|
|
),
|
|
country: createRangeRecord((range) => buildCountryStats(geo, getWindow(range, earliest, latest))),
|
|
}
|
|
}
|
|
|
|
function buildStatsModelData(
|
|
modelParam: string,
|
|
modelRows: ModelStatMetric[],
|
|
geoRows: GeoStatMetric[],
|
|
providerParam?: string,
|
|
): StatsModelData | null {
|
|
const normalized = modelRows.flatMap(normalizeStatRow)
|
|
const geo = geoRows.flatMap(normalizeGeoRow)
|
|
if (normalized.length === 0) return null
|
|
|
|
const model = resolveModelName(modelParam, normalized, providerParam)
|
|
if (!model) return null
|
|
|
|
const modelScopedRows = normalized.filter((row) => row.model === model)
|
|
const earliest = Math.min(...normalized.map((row) => row.periodStart))
|
|
const latest = Math.max(...normalized.map((row) => row.periodStart))
|
|
const latestUpdate = Math.max(...modelScopedRows.map((row) => row.updatedAt))
|
|
const window = getWindow("2M", earliest, latest)
|
|
const currentRows = rowsForProduct(modelScopedRows, "All Users", window.start, window.end)
|
|
const previousRows = rowsForProduct(modelScopedRows, "All Users", window.previousStart, window.previousEnd)
|
|
const current = combineRowsForModel(model, currentRows)
|
|
const previous = combineRowsForModel(model, previousRows)
|
|
const peers = aggregateByModelName(rowsForProduct(normalized, "All Users", window.start, window.end))
|
|
.filter((item) => item.totalTokens > 0)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.model.localeCompare(b.model))
|
|
const previousPeers = aggregateByModelName(
|
|
rowsForProduct(normalized, "All Users", window.previousStart, window.previousEnd),
|
|
)
|
|
.filter((item) => item.totalTokens > 0)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.model.localeCompare(b.model))
|
|
const rank = Math.max(1, peers.findIndex((item) => item.model === model) + 1)
|
|
const previousRankIndex = previousPeers.findIndex((item) => item.model === model)
|
|
const totalTokens = peers.reduce((sum, item) => sum + item.totalTokens, 0)
|
|
|
|
return {
|
|
updatedAt: Number.isFinite(latestUpdate) ? new Date(latestUpdate).toISOString() : null,
|
|
model,
|
|
slug: modelSlug(model),
|
|
provider: current.provider,
|
|
author: formatProvider(current.provider),
|
|
rank,
|
|
previousRank: previousRankIndex >= 0 ? previousRankIndex + 1 : null,
|
|
totalModels: peers.length,
|
|
tokenShare: totalTokens > 0 ? round((current.totalTokens / totalTokens) * 100, 2) : 0,
|
|
tokenChange: percentChange(current.totalTokens, previous.totalTokens),
|
|
totals: {
|
|
sessions: current.sessions,
|
|
tokens: current.totalTokens,
|
|
cost: round(microcentsToDollars(current.totalCostMicrocents), 2),
|
|
tokensPerSession: current.sessions > 0 ? Math.round(current.totalTokens / current.sessions) : 0,
|
|
costPerSession:
|
|
current.sessions > 0 ? round(microcentsToDollars(current.totalCostMicrocents) / current.sessions, 4) : 0,
|
|
costPerMillion: costPerMillion(current.totalCostMicrocents, current.totalTokens),
|
|
cacheRatio:
|
|
current.inputTokens + current.cacheReadTokens > 0
|
|
? round((current.cacheReadTokens / (current.inputTokens + current.cacheReadTokens)) * 100, 1)
|
|
: 0,
|
|
},
|
|
usage: buildModelUsage(currentRows, window, "2M"),
|
|
tokenMix: buildModelTokenMix(current),
|
|
productMix: buildModelProductMix(modelScopedRows, window, current),
|
|
country: createRangeRecord((range) => buildCountryStats(geo, getWindow(range, earliest, latest))),
|
|
peers: buildModelPeers(peers, rank, totalTokens),
|
|
}
|
|
}
|
|
|
|
function buildStatsLabData(providerParam: string, modelRows: ModelStatMetric[]): StatsLabData | null {
|
|
const normalized = modelRows.flatMap(normalizeStatRow)
|
|
if (normalized.length === 0) return null
|
|
|
|
const provider = resolveProviderName(providerParam, normalized)
|
|
if (!provider) return null
|
|
|
|
const providerRows = normalized.filter((row) => providerMatches(row.provider, provider))
|
|
if (providerRows.length === 0) return null
|
|
|
|
const earliest = Math.min(...normalized.map((row) => row.periodStart))
|
|
const latest = Math.max(...normalized.map((row) => row.periodStart))
|
|
const latestUpdate = Math.max(...providerRows.map((row) => row.updatedAt))
|
|
const window = getWindow("2M", earliest, latest)
|
|
const currentRows = rowsForProduct(providerRows, "All Users", window.start, window.end)
|
|
const previousRows = rowsForProduct(providerRows, "All Users", window.previousStart, window.previousEnd)
|
|
const current = combineRowsForModel("", currentRows)
|
|
const previous = combineRowsForModel("", previousRows)
|
|
const allCurrent = aggregateByModel(rowsForProduct(normalized, "All Users", window.start, window.end))
|
|
const totalTokens = allCurrent.reduce((sum, item) => sum + item.totalTokens, 0)
|
|
const models = aggregateByModel(currentRows)
|
|
.filter((item) => item.totalTokens > 0)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.model.localeCompare(b.model))
|
|
|
|
return {
|
|
updatedAt: Number.isFinite(latestUpdate) ? new Date(latestUpdate).toISOString() : null,
|
|
provider,
|
|
author: formatProvider(provider),
|
|
tokenShare: totalTokens > 0 ? round((current.totalTokens / totalTokens) * 100, 2) : 0,
|
|
tokenChange: percentChange(current.totalTokens, previous.totalTokens),
|
|
totals: {
|
|
sessions: current.sessions,
|
|
tokens: current.totalTokens,
|
|
models: models.length,
|
|
},
|
|
usage: buildModelUsage(currentRows, window, "2M"),
|
|
models: models.map((item) => ({
|
|
model: item.model,
|
|
provider: item.provider,
|
|
author: formatProvider(item.provider),
|
|
tokens: item.totalTokens,
|
|
share: current.totalTokens > 0 ? round((item.totalTokens / current.totalTokens) * 100, 2) : 0,
|
|
slug: modelSlug(item.model),
|
|
})),
|
|
}
|
|
}
|
|
|
|
function emptyStatsHomeData(): StatsHomeData {
|
|
return {
|
|
updatedAt: null,
|
|
usage: createUsageProductRecord(() => createRangeRecord(() => [])),
|
|
leaderboard: createUsageProductRecord(() => createRangeRecord(() => [])),
|
|
market: createRangeRecord(() => []),
|
|
tokenCost: createTokenProductRecord(() => []),
|
|
cacheRatio: createTokenProductRecord(() => []),
|
|
sessionCost: createTokenProductRecord(() => []),
|
|
country: createRangeRecord(() => []),
|
|
}
|
|
}
|
|
|
|
function buildUsagePoints(rows: StatMetricRow[], product: UsageProduct, range: UsageRange, window: DateWindow) {
|
|
const windowRows = rowsForProduct(rows, product, window.start, window.end)
|
|
const modelOrder = aggregateByModel(windowRows)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens)
|
|
.slice(0, 6)
|
|
.map((item) => ({ key: modelKey(item.provider, item.model), model: item.model }))
|
|
|
|
return createBuckets(window, range).map((bucket) => {
|
|
const bucketRows = aggregateByModel(rowsForProduct(rows, product, bucket.start, bucket.end))
|
|
const byModel = new Map(bucketRows.map((item) => [modelKey(item.provider, item.model), item.totalTokens]))
|
|
const segmentTokens = modelOrder.map((model) => ({ model: model.model, tokens: byModel.get(model.key) ?? 0 }))
|
|
const knownTokens = segmentTokens.reduce((sum, item) => sum + item.tokens, 0)
|
|
const totalTokens = bucketRows.reduce((sum, item) => sum + item.totalTokens, 0)
|
|
return {
|
|
date: bucket.label,
|
|
segments: [
|
|
...segmentTokens.map((item) => ({ model: item.model, value: round(item.tokens / 1_000_000_000_000, 4) })),
|
|
{ model: "Other", value: round(Math.max(totalTokens - knownTokens, 0) / 1_000_000_000_000, 4) },
|
|
],
|
|
}
|
|
})
|
|
}
|
|
|
|
function buildLeaderboard(rows: StatMetricRow[], product: UsageProduct, window: DateWindow) {
|
|
const previous = new Map(
|
|
aggregateByModel(rowsForProduct(rows, product, window.previousStart, window.previousEnd)).map((item) => [
|
|
modelKey(item.provider, item.model),
|
|
item.totalTokens,
|
|
]),
|
|
)
|
|
|
|
return aggregateByModel(rowsForProduct(rows, product, window.start, window.end))
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens)
|
|
.slice(0, 18)
|
|
.map((item, index) => ({
|
|
model: item.model,
|
|
provider: item.provider,
|
|
author: formatProvider(item.provider),
|
|
tokens: Math.round(item.totalTokens / 1_000_000_000),
|
|
change: leaderboardChange(item.totalTokens, previous.get(modelKey(item.provider, item.model)) ?? 0),
|
|
rank: index + 1,
|
|
}))
|
|
}
|
|
|
|
function buildMarketShare(rows: ProviderMetricRow[], product: UsageProduct, range: UsageRange, window: DateWindow) {
|
|
return createBuckets(window, range).flatMap((bucket) => {
|
|
const total = aggregateByProvider(rowsForProduct(rows, product, bucket.start, bucket.end)).toSorted(
|
|
(a, b) => b.tokens - a.tokens,
|
|
)
|
|
const totalTokens = total.reduce((sum, item) => sum + item.tokens, 0)
|
|
if (totalTokens === 0) return []
|
|
|
|
const authors = total.slice(0, 8)
|
|
const knownTokens = authors.reduce((sum, item) => sum + item.tokens, 0)
|
|
const withOther = [...authors, { provider: "Other", tokens: Math.max(totalTokens - knownTokens, 0) }].filter(
|
|
(item) => item.tokens > 0,
|
|
)
|
|
|
|
return [
|
|
{
|
|
date: bucket.label,
|
|
total: round(totalTokens / 1_000_000_000_000, 2),
|
|
authors: withOther.map((item) => ({
|
|
author: item.provider === "Other" ? "Other" : formatProvider(item.provider),
|
|
share: round((item.tokens / totalTokens) * 100, 1),
|
|
tokens: round(item.tokens / 1_000_000_000_000, 2),
|
|
})),
|
|
},
|
|
]
|
|
})
|
|
}
|
|
|
|
function buildCountryStats(rows: GeoMetricRow[], window: DateWindow) {
|
|
const countries = aggregateByCountry(rowsForProduct(rows, "All Users", window.start, window.end))
|
|
.filter((item) => item.tokens > 0 && item.country !== "AQ")
|
|
.toSorted((a, b) => b.tokens - a.tokens)
|
|
const totalTokens = countries.reduce((sum, item) => sum + item.tokens, 0)
|
|
if (totalTokens === 0) return []
|
|
|
|
return countries.map((item, index) => ({
|
|
country: item.country,
|
|
continent: item.continent,
|
|
tokens: round(item.tokens / 1_000_000_000_000, 4),
|
|
share: round((item.tokens / totalTokens) * 100, 1),
|
|
rank: index + 1,
|
|
}))
|
|
}
|
|
|
|
function buildTokenCost(rows: StatMetricRow[], product: TokenProduct, window: DateWindow) {
|
|
return topModelsByUsage(rows, product, window)
|
|
.flatMap((item) => {
|
|
const total = costPerMillion(item.totalCostMicrocents, item.totalTokens)
|
|
if (total === 0) return []
|
|
return [
|
|
{
|
|
model: item.model,
|
|
total,
|
|
input: costPerMillion(item.inputCostMicrocents, item.inputTokens),
|
|
output: costPerMillion(item.outputCostMicrocents, item.outputTokens + item.reasoningTokens),
|
|
cached: costPerMillion(item.inputCostMicrocents, item.inputTokens + item.cacheReadTokens),
|
|
},
|
|
]
|
|
})
|
|
.toSorted((a, b) => a.total - b.total)
|
|
}
|
|
|
|
function buildCacheRatio(rows: StatMetricRow[], product: TokenProduct, window: DateWindow) {
|
|
return topModelsByUsage(rows, product, window)
|
|
.flatMap((item) => {
|
|
const total = item.inputTokens + item.cacheReadTokens
|
|
if (total === 0) return []
|
|
return [
|
|
{
|
|
model: item.model,
|
|
ratio: round((item.cacheReadTokens / total) * 100, 1),
|
|
cached: round(item.cacheReadTokens / 1_000_000_000, 1),
|
|
uncached: round(item.inputTokens / 1_000_000_000, 1),
|
|
total: round(total / 1_000_000_000, 1),
|
|
},
|
|
]
|
|
})
|
|
.toSorted((a, b) => b.ratio - a.ratio || b.cached - a.cached)
|
|
}
|
|
|
|
function buildSessionCost(rows: StatMetricRow[], product: TokenProduct, window: DateWindow) {
|
|
return topModelsByUsage(rows, product, window)
|
|
.flatMap((item) => {
|
|
if (item.sessions === 0) return []
|
|
const cost = round(microcentsToDollars(item.totalCostMicrocents) / item.sessions, 4)
|
|
if (cost === 0) return []
|
|
return [{ model: item.model, cost, tokens: Math.round(item.totalTokens / item.sessions) }]
|
|
})
|
|
.toSorted((a, b) => a.cost - b.cost)
|
|
}
|
|
|
|
function topModelsByUsage(rows: StatMetricRow[], product: TokenProduct, window: DateWindow) {
|
|
return aggregateByModel(rowsForProduct(rows, product, window.start, window.end))
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens)
|
|
.slice(0, METRIC_MODEL_LIMIT)
|
|
}
|
|
|
|
function buildModelUsage(rows: StatMetricRow[], window: DateWindow, range: UsageRange) {
|
|
return createBuckets(window, range).map((bucket) => {
|
|
const aggregate = combineRowsForModel(
|
|
"",
|
|
rows.filter((row) => row.periodStart >= bucket.start && row.periodStart < bucket.end),
|
|
)
|
|
return {
|
|
date: bucket.label,
|
|
tokens: aggregate.totalTokens,
|
|
sessions: aggregate.sessions,
|
|
cost: round(microcentsToDollars(aggregate.totalCostMicrocents), 2),
|
|
}
|
|
})
|
|
}
|
|
|
|
function buildModelTokenMix(aggregate: ModelAggregate): ModelMixEntry[] {
|
|
const items = [
|
|
{ label: "Input", tokens: aggregate.inputTokens },
|
|
{ label: "Output", tokens: aggregate.outputTokens },
|
|
{ label: "Reasoning", tokens: aggregate.reasoningTokens },
|
|
{ label: "Cached", tokens: aggregate.cacheReadTokens },
|
|
].filter((item) => item.tokens > 0)
|
|
const total = items.reduce((sum, item) => sum + item.tokens, 0)
|
|
if (total === 0) return []
|
|
return items.map((item) => ({ ...item, share: round((item.tokens / total) * 100, 1) }))
|
|
}
|
|
|
|
function buildModelProductMix(
|
|
rows: StatMetricRow[],
|
|
window: DateWindow,
|
|
fallback: ModelAggregate,
|
|
): ModelProductEntry[] {
|
|
const products = ["Go", "Zen", "Enterprise"] as const
|
|
const items = products.flatMap((product) => {
|
|
const aggregate = combineRowsForModel(
|
|
fallback.model,
|
|
rows.filter((row) => row.tier === product && row.periodStart >= window.start && row.periodStart < window.end),
|
|
)
|
|
if (aggregate.totalTokens === 0) return []
|
|
return [{ product, tokens: aggregate.totalTokens, sessions: aggregate.sessions }]
|
|
})
|
|
const total = items.reduce((sum, item) => sum + item.tokens, 0)
|
|
if (total > 0) return items.map((item) => ({ ...item, share: round((item.tokens / total) * 100, 1) }))
|
|
if (fallback.totalTokens === 0) return []
|
|
return [{ product: "All Users", tokens: fallback.totalTokens, sessions: fallback.sessions, share: 100 }]
|
|
}
|
|
|
|
function buildModelPeers(peers: ModelAggregate[], rank: number, totalTokens: number): ModelPeerEntry[] {
|
|
const start = Math.max(0, Math.min(rank - 4, Math.max(peers.length - 7, 0)))
|
|
return peers.slice(start, start + 7).map((item, index) => ({
|
|
model: item.model,
|
|
provider: item.provider,
|
|
author: formatProvider(item.provider),
|
|
rank: start + index + 1,
|
|
tokens: item.totalTokens,
|
|
share: totalTokens > 0 ? round((item.totalTokens / totalTokens) * 100, 2) : 0,
|
|
slug: modelSlug(item.model),
|
|
}))
|
|
}
|
|
|
|
function rowsForProduct<T extends { periodStart: number; tier: string }>(
|
|
rows: T[],
|
|
product: UsageProduct,
|
|
start: number,
|
|
end: number,
|
|
) {
|
|
const windowRows = rows.filter((row) => row.periodStart >= start && row.periodStart < end)
|
|
if (product !== "All Users") return windowRows.filter((row) => row.tier === product)
|
|
|
|
const allRows = windowRows.filter((row) => row.tier === "all")
|
|
if (allRows.length > 0) return allRows
|
|
return windowRows.filter((row) => row.tier !== "all")
|
|
}
|
|
|
|
function aggregateByModel(rows: StatMetricRow[]) {
|
|
return Object.values(
|
|
rows.reduce<Record<string, ModelAggregate>>((result, row) => {
|
|
const key = modelKey(row.provider, row.model)
|
|
result[key] = combineModelAggregate(result[key], row)
|
|
return result
|
|
}, {}),
|
|
)
|
|
}
|
|
|
|
function aggregateByModelName(rows: StatMetricRow[]) {
|
|
return Object.values(
|
|
rows.reduce<Record<string, ModelAggregate>>((result, row) => {
|
|
result[row.model] = combineModelAggregate(result[row.model], row)
|
|
return result
|
|
}, {}),
|
|
)
|
|
}
|
|
|
|
function aggregateByProvider(rows: ProviderMetricRow[]) {
|
|
return Object.values(
|
|
rows.reduce<Record<string, { provider: string; tokens: number }>>((result, row) => {
|
|
result[row.provider] = {
|
|
provider: row.provider,
|
|
tokens: (result[row.provider]?.tokens ?? 0) + row.totalTokens,
|
|
}
|
|
return result
|
|
}, {}),
|
|
)
|
|
}
|
|
|
|
function aggregateByCountry(rows: GeoMetricRow[]) {
|
|
return Object.values(
|
|
rows.reduce<Record<string, { country: string; continent: string; tokens: number }>>((result, row) => {
|
|
result[row.country] = {
|
|
country: row.country,
|
|
continent: result[row.country]?.continent || row.continent,
|
|
tokens: (result[row.country]?.tokens ?? 0) + row.totalTokens,
|
|
}
|
|
return result
|
|
}, {}),
|
|
)
|
|
}
|
|
|
|
function combineRowsForModel(model: string, rows: StatMetricRow[]): ModelAggregate {
|
|
const aggregate = rows.reduce<ModelAggregate | undefined>(
|
|
(result, row) => combineModelAggregate(result, row),
|
|
undefined,
|
|
)
|
|
if (aggregate) return { ...aggregate, model: model || aggregate.model }
|
|
return {
|
|
model,
|
|
provider: "unknown",
|
|
sessions: 0,
|
|
inputTokens: 0,
|
|
outputTokens: 0,
|
|
reasoningTokens: 0,
|
|
cacheReadTokens: 0,
|
|
totalTokens: 0,
|
|
inputCostMicrocents: 0,
|
|
outputCostMicrocents: 0,
|
|
totalCostMicrocents: 0,
|
|
}
|
|
}
|
|
|
|
function combineModelAggregate(current: ModelAggregate | undefined, row: StatMetricRow): ModelAggregate {
|
|
return {
|
|
model: row.model,
|
|
provider: row.provider,
|
|
sessions: (current?.sessions ?? 0) + row.sessions,
|
|
inputTokens: (current?.inputTokens ?? 0) + row.inputTokens,
|
|
outputTokens: (current?.outputTokens ?? 0) + row.outputTokens,
|
|
reasoningTokens: (current?.reasoningTokens ?? 0) + row.reasoningTokens,
|
|
cacheReadTokens: (current?.cacheReadTokens ?? 0) + row.cacheReadTokens,
|
|
totalTokens: (current?.totalTokens ?? 0) + row.totalTokens,
|
|
inputCostMicrocents: (current?.inputCostMicrocents ?? 0) + row.inputCostMicrocents,
|
|
outputCostMicrocents: (current?.outputCostMicrocents ?? 0) + row.outputCostMicrocents,
|
|
totalCostMicrocents: (current?.totalCostMicrocents ?? 0) + row.totalCostMicrocents,
|
|
}
|
|
}
|
|
|
|
function getWindow(range: UsageRange, earliest: number, latest: number): DateWindow {
|
|
const end = latest + DAY_MS
|
|
const start = Math.max(
|
|
earliest,
|
|
range === "1D"
|
|
? latest
|
|
: range === "1W"
|
|
? latest - 6 * DAY_MS
|
|
: range === "2W"
|
|
? latest - 13 * DAY_MS
|
|
: range === "1M"
|
|
? latest - 27 * DAY_MS
|
|
: range === "2M"
|
|
? latest - 55 * DAY_MS
|
|
: range === "3M"
|
|
? latest - 89 * DAY_MS
|
|
: range === "YTD"
|
|
? Date.UTC(new Date(latest).getUTCFullYear(), 0, 1)
|
|
: earliest,
|
|
)
|
|
const duration = end - start
|
|
return { start, end, previousStart: start - duration, previousEnd: start }
|
|
}
|
|
|
|
function createBuckets(window: DateWindow, range: UsageRange): Bucket[] {
|
|
const span = Math.max(window.end - window.start, DAY_MS)
|
|
const count =
|
|
range === "1D"
|
|
? 1
|
|
: range === "1W" || range === "2W" || range === "1M" || range === "2M" || range === "3M"
|
|
? Math.ceil(span / DAY_MS)
|
|
: Math.max(1, Math.min(7, Math.ceil(span / DAY_MS)))
|
|
const size = span / count
|
|
return Array.from({ length: count }, (_, index) => {
|
|
const start = window.start + index * size
|
|
const end = index === count - 1 ? window.end : window.start + (index + 1) * size
|
|
return { start, end, label: formatBucketLabel(start, end, range) }
|
|
})
|
|
}
|
|
|
|
function createUsageProductRecord<T>(value: (product: UsageProduct) => T): Record<UsageProduct, T> {
|
|
return {
|
|
"All Users": value("All Users"),
|
|
Zen: value("Zen"),
|
|
Go: value("Go"),
|
|
Enterprise: value("Enterprise"),
|
|
}
|
|
}
|
|
|
|
function createTokenProductRecord<T>(value: (product: TokenProduct) => T): Record<TokenProduct, T> {
|
|
return {
|
|
Zen: value("Zen"),
|
|
Go: value("Go"),
|
|
Enterprise: value("Enterprise"),
|
|
}
|
|
}
|
|
|
|
function createRangeRecord<T>(value: (range: UsageRange) => T): Record<UsageRange, T> {
|
|
return {
|
|
"1D": value("1D"),
|
|
"1W": value("1W"),
|
|
"2W": value("2W"),
|
|
"1M": value("1M"),
|
|
"2M": value("2M"),
|
|
"3M": value("3M"),
|
|
YTD: value("YTD"),
|
|
ALL: value("ALL"),
|
|
}
|
|
}
|
|
|
|
function normalizeStatRow(row: ModelStatMetric): StatMetricRow[] {
|
|
const periodStart = periodKeyTime(row.periodKey)
|
|
const updatedAt = dateTime(row.updatedAt)
|
|
if (!Number.isFinite(periodStart) || !Number.isFinite(updatedAt)) return []
|
|
return [
|
|
{
|
|
...row,
|
|
periodStart,
|
|
updatedAt,
|
|
tier: normalizeTier(row.tier),
|
|
provider: row.provider || "unknown",
|
|
model: row.model || "unknown",
|
|
},
|
|
]
|
|
}
|
|
|
|
function normalizeProviderRow(row: ProviderStatMetric): ProviderMetricRow[] {
|
|
const periodStart = periodKeyTime(row.periodKey)
|
|
const updatedAt = dateTime(row.updatedAt)
|
|
if (!Number.isFinite(periodStart) || !Number.isFinite(updatedAt)) return []
|
|
return [
|
|
{
|
|
...row,
|
|
periodStart,
|
|
updatedAt,
|
|
tier: normalizeTier(row.tier),
|
|
provider: row.provider || "unknown",
|
|
},
|
|
]
|
|
}
|
|
|
|
function normalizeGeoRow(row: GeoStatMetric): GeoMetricRow[] {
|
|
const periodStart = periodKeyTime(row.periodKey)
|
|
const updatedAt = dateTime(row.updatedAt)
|
|
if (!Number.isFinite(periodStart) || !Number.isFinite(updatedAt)) return []
|
|
return [
|
|
{
|
|
...row,
|
|
periodStart,
|
|
updatedAt,
|
|
tier: normalizeTier(row.tier),
|
|
provider: row.provider || "all",
|
|
model: row.model || "all",
|
|
country: row.country || "ZZ",
|
|
continent: row.continent || "",
|
|
},
|
|
]
|
|
}
|
|
|
|
function normalizeTier(value: string) {
|
|
const normalized = value.toLowerCase()
|
|
if (normalized === "paid" || normalized === "zen") return "Zen"
|
|
if (normalized === "go") return "Go"
|
|
if (normalized === "enterprise") return "Enterprise"
|
|
if (normalized === "all") return "all"
|
|
return value
|
|
}
|
|
|
|
function dateTime(value: Date | string) {
|
|
return (value instanceof Date ? value : new Date(value)).getTime()
|
|
}
|
|
|
|
function periodKeyTime(value: string) {
|
|
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value)
|
|
if (!match) return Number.NaN
|
|
return Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
|
|
}
|
|
|
|
function formatBucketLabel(start: number, _end: number, range: UsageRange) {
|
|
const date = new Date(start)
|
|
if (range === "YTD") return months[date.getUTCMonth()]
|
|
if (range === "ALL")
|
|
return date.getUTCFullYear() === new Date().getUTCFullYear()
|
|
? months[date.getUTCMonth()]
|
|
: String(date.getUTCFullYear())
|
|
return formatDay(start)
|
|
}
|
|
|
|
function formatDay(value: number) {
|
|
const date = new Date(value)
|
|
return `${months[date.getUTCMonth()]} ${date.getUTCDate()}`
|
|
}
|
|
|
|
function formatProvider(provider: string) {
|
|
const known: Record<string, string> = {
|
|
anthropic: "Anthropic",
|
|
deepseek: "DeepSeek",
|
|
google: "Google",
|
|
minimax: "MiniMax",
|
|
moonshot: "Moonshot",
|
|
moonshotai: "Moonshot",
|
|
nvidia: "NVIDIA",
|
|
opencode: "opencode",
|
|
openai: "OpenAI",
|
|
qwen: "Qwen",
|
|
tencent: "Tencent",
|
|
xai: "xAI",
|
|
xiaomi: "Xiaomi",
|
|
zhipu: "Zhipu",
|
|
zhipuai: "Zhipu",
|
|
}
|
|
const normalized = provider.toLowerCase().replace(/[^a-z0-9]/g, "")
|
|
return known[normalized] ?? provider.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase())
|
|
}
|
|
|
|
function resolveModelName(modelParam: string, rows: StatMetricRow[], providerParam?: string) {
|
|
const input = modelParam.trim()
|
|
if (!input) return undefined
|
|
const normalizedInput = input.toLowerCase()
|
|
const inputSlug = modelSlug(input)
|
|
const candidates = providerParam
|
|
? aggregateByModel(rows).filter((item) => providerMatches(item.provider, providerParam))
|
|
: aggregateByModelName(rows)
|
|
return candidates
|
|
.filter((item) => item.model.toLowerCase() === normalizedInput || modelSlug(item.model) === inputSlug)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.model.localeCompare(b.model))[0]?.model
|
|
}
|
|
|
|
function resolveModelProvider(model: string, rows: StatMetricRow[], providerParam?: string) {
|
|
return aggregateByModel(rows)
|
|
.filter((item) => item.model === model && (!providerParam || providerMatches(item.provider, providerParam)))
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.provider.localeCompare(b.provider))[0]?.provider
|
|
}
|
|
|
|
function providerMatches(provider: string, providerParam: string) {
|
|
return modelSlug(provider) === modelSlug(providerParam)
|
|
}
|
|
|
|
function resolveProviderName(providerParam: string, rows: StatMetricRow[]) {
|
|
const input = providerParam.trim()
|
|
if (!input) return undefined
|
|
const inputSlug = modelSlug(input)
|
|
return aggregateByModel(rows)
|
|
.filter((item) => modelSlug(item.provider) === inputSlug)
|
|
.toSorted((a, b) => b.totalTokens - a.totalTokens || a.provider.localeCompare(b.provider))[0]?.provider
|
|
}
|
|
|
|
export function modelSlug(value: string) {
|
|
return value
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, "-")
|
|
.replace(/^-+|-+$/g, "")
|
|
.replace(/-{2,}/g, "-")
|
|
}
|
|
|
|
function modelKey(provider: string, model: string) {
|
|
return `${provider}\u0000${model}`
|
|
}
|
|
|
|
function costPerMillion(costMicrocents: number, tokens: number) {
|
|
if (tokens <= 0 || costMicrocents <= 0) return 0
|
|
return round((microcentsToDollars(costMicrocents) / tokens) * TOKEN_SCALE, 2)
|
|
}
|
|
|
|
function microcentsToDollars(value: number) {
|
|
return value * DOLLARS_PER_MICROCENT
|
|
}
|
|
|
|
function percentChange(current: number, previous: number) {
|
|
if (previous <= 0) return current > 0 ? 100 : 0
|
|
return Math.round(((current - previous) / previous) * 100)
|
|
}
|
|
|
|
function leaderboardChange(current: number, previous: number) {
|
|
if (current <= 0) return 0
|
|
if (previous <= 0 || current >= previous * LEADERBOARD_CHANGE_MIN_MULTIPLE) return null
|
|
return percentChange(current, previous)
|
|
}
|
|
|
|
function round(value: number, digits: number) {
|
|
return Number(value.toFixed(digits))
|
|
}
|