/** * Types mirroring docs/API.md (contract v1). Postgres aggregates may arrive as strings → `Num`; always go through `num()`/`fmt*`. * Unknown/extra keys are tolerated: the web layer only reads what it renders. */ export type Num = number | string | null; export type Org = { id: string; slug: string; name: string } | null; export type Quality = { score?: number; completeness?: number; primary_source_ratio?: number; freshness?: number; source_count?: number; conflicts?: number }; export type Counts = { relations?: number; events?: number; claims?: number }; export interface EntitySummary { id: string; entity_type: string; slug: string; name: string; description: string | null; status: string; organization: Org; attributes: Record; quality: Quality; counts: Counts; first_seen_at: string; last_seen_at: string; updated_at: string; } export interface Page { items: T[]; total: number; limit: number; offset: number; } export type ProvenanceEntry = { source_id: string | null; source_name?: string; url: string | null; observed_at: string; tier: number; confidence: string; extractor: string; unit?: string; }; export type Provenance = Record; export type Importance = 0 | 1 | 2 | 3; export interface ChangeEvent { id: string; event_type: string; category: string; property: string | null; old_value: unknown; new_value: unknown; summary: string; importance: Importance; observed_at: string; effective_at: string | null; source_url: string | null; connector_name: string | null; entity: EntitySummary | null; meta: Record; } export interface Price { id: string; model: EntitySummary; provider: EntitySummary; provider_model_id: string | null; input_per_mtok: Num; output_per_mtok: Num; cached_input_per_mtok: Num; cache_write_per_mtok: Num; batch_input_per_mtok: Num; batch_output_per_mtok: Num; per_image: Num; currency: string; context_length: Num; max_output_tokens: Num; features: Record; observed_at: string; valid_from: string; valid_to: string | null; source_url: string | null; tier: number; } export interface BenchmarkResult { id: string; model: EntitySummary; benchmark: EntitySummary; score: number; metric: string | null; unit: string | null; higher_is_better: boolean; config: Record; evaluated_at: string | null; observed_at: string; source_url: string | null; tier: number; confidence: string; } export interface Claim { id: string; property: string; value: unknown; unit: string | null; tier: number; confidence: string; status: string; extractor: string; observed_at: string; effective_at: string | null; valid_from: string; valid_to: string | null; source_url: string | null; source_name: string | null; } export interface SourceRef { source_id: string | null; source_name: string | null; domain: string | null; tier: number | null; url: string; doc_type: string; last_observed_at: string | null; snapshots: number; } export interface RelationGroup { predicate: string; direction: 'out' | 'in'; items: EntitySummary[]; total: number; } export interface Lineage { ancestors: EntitySummary[]; descendants: EntitySummary[]; quantizations: EntitySummary[]; } export interface HardwareFitRow { hardware: EntitySummary; quantization: string; estimated_memory_gb: number; fits: boolean; } export interface EntityDetail extends EntitySummary { provenance: Provenance; aliases: string[]; identifiers: { scheme: string; value: string }[]; relations: RelationGroup[]; sources: SourceRef[]; timeline: ChangeEvent[]; prices?: Price[]; price_history?: Price[]; results?: BenchmarkResult[]; lineage?: Lineage; providers?: EntitySummary[]; hardware_fit?: HardwareFitRow[]; models?: Page; papers?: EntitySummary[]; repositories?: EntitySummary[]; // companies listing enrichments may also be present on detail model_count?: number; paper_count?: number; } export interface Health { status: 'ok' | 'degraded' | string; version: string; db: boolean; redis: boolean; llm: { available: boolean; reachable?: boolean }; time: string; } export interface Stats { entities: Record; entities_total: Num; sources: Num; connectors: Num; connectors_enabled: Num; documents: Num; snapshots: Num; claims: Num; claims_current: Num; relations: Num; change_events: Num; change_events_24h: Num; change_events_7d: Num; benchmark_results: Num; prices_current: Num; prices_total: Num; review_pending: Num; llm_jobs: Num; llm_tokens: Num; last_snapshot_at: string | null; last_event_at: string | null; first_entity_at: string | null; archive: { raw_bytes: Num; raw_files: Num; text_bytes: Num; text_files: Num }; computed_at: string; } export interface StatsHistory { items: { day: string; counts: Record }[]; } /** Output of services.search.compile_query — shape is loose; we render what we recognise. */ export interface CompiledQuery { text?: string | null; q?: string | null; entity_type?: string | null; type?: string | null; filters?: Record; [k: string]: unknown; } export interface SearchPayload { query: CompiledQuery; items: (EntitySummary & { rank: number })[]; total: number; } export interface Suggestion { id: string; entity_type: string; slug: string; name: string; organization_name: string | null; } export interface FacetValue { value: string; count: Num; } export interface OrgFacet { slug: string; name: string; count: Num; } export interface ModelFacets { organizations?: OrgFacet[]; openness?: FacetValue[]; modalities?: FacetValue[]; families?: FacetValue[]; years?: FacetValue[]; licenses?: FacetValue[]; status?: FacetValue[]; } export type ModelsPage = Page & { facets?: ModelFacets }; export type CompanyRow = EntitySummary & { model_count: Num; paper_count: Num }; export interface CompanyFacets { countries?: FacetValue[]; kinds?: FacetValue[]; } export type CompaniesPage = Page & { facets?: CompanyFacets }; export type ProviderRow = EntitySummary & { model_count: Num; price_count: Num; min_input_per_mtok: Num; min_output_per_mtok: Num }; export type BenchmarkRow = EntitySummary & { result_count: Num; model_count: Num; top: { model: EntitySummary; score: number } | null }; export interface PriceIndexPoint { day: string; median_input: Num; median_output: Num; min_input: Num; max_input?: Num; models: number; offers?: number; } export interface PriceIndex { days?: number; note?: string; series: PriceIndexPoint[]; movers: ChangeEvent[]; } export interface HardwareFitItem { model: EntitySummary; parameter_count: number; estimated_memory_gb: number; fits: boolean; headroom_gb: number; quantization: string; note: string; } export interface HardwareFit { inputs: Record; estimated?: boolean; counts?: { fits?: Num; evaluated?: Num }; assumptions: string[]; items: HardwareFitItem[]; } export interface ExploreType { entity_type: string; count: Num; label: string; } export interface DailyDigest { date: string; counts: Record; sections: { category: string; label: string; items: ChangeEvent[] }[]; new_models: EntitySummary[]; } export interface ChangeCategories { items: { category: string; event_type: string; count: Num }[]; } export interface TimelinePayload { items: { month: string; count?: number; events: ChangeEvent[] }[]; total?: number; } export interface CompareDimension { key: string; label: string; unit?: string; kind: 'number' | 'text' | 'list' | 'bool' | 'date'; /** Where the value comes from: `attr` (claims) · `prices` · `results` (benchmark) — informational. */ source?: string; } export interface ComparePayload { entity_type: string; dimensions: CompareDimension[]; items: { entity: EntitySummary; values: Record; provenance: Provenance; prices?: Price[]; results?: BenchmarkResult[] }[]; } export interface DiffPayload { a: string; b: string; scope?: Record | string; new_entities: EntitySummary[]; gone_entities: EntitySummary[]; property_changes: ChangeEvent[]; price_changes: ChangeEvent[]; benchmark_changes: ChangeEvent[]; counts: Record; } export interface ConnectorHealth { name: string; label: string; health: string; last_success_at: string | null; interval_seconds: Num; } export interface SourceRow { key: string; name: string; domain: string; tier: number; kind: string; category: string; organization: Org; enabled: boolean; documents: Num; last_crawled_at: string | null; connectors: ConnectorHealth[]; } export interface MetricDefinition { key?: string; name?: string; label?: string; description?: string; formula?: string; version?: string | number; unit?: string; [k: string]: unknown; } export interface Methodology { metrics: MetricDefinition[]; confidence_levels: Record | { key: string; label?: string; description?: string }[] | string[]; tiers: Record | { tier: number; label?: string; description?: string }[]; event_types: Record | { event_type: string; category?: string; label?: string; description?: string; importance?: number }[] | string[]; extractors: Record | { key?: string; name?: string; description?: string }[] | string[]; } export type TrendingRow = EntitySummary & { views: Num }; export interface SitemapPayload { items: { slug: string; entity_type: string; updated_at: string }[]; total: number; } export interface GraphNode { id: string; slug: string; name: string; entity_type: string; organization_name?: string | null; } export interface GraphEdge { source: string; target: string; predicate: string; } export interface GraphPayload { root?: string; nodes: GraphNode[]; edges: GraphEdge[]; } export interface AsOfPayload { id?: string; slug?: string; name?: string; entity_type?: string; existed: boolean; first_seen_at: string | null; date: string; attributes: Record; claims: Claim[]; }