codex-helper-core 0.15.0

Core library for codex-helper.
Documentation
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::dashboard_core::WindowStats;
use crate::dashboard_core::types::{ControlProfileOption, StationOption};
use crate::dashboard_core::window_stats::compute_window_stats;
use crate::state::{
    ActiveRequest, FinishedRequest, HealthCheckStatus, LbConfigView, ProviderBalanceSnapshot,
    ProxyState, SessionIdentityCard, SessionIdentityCardBuildInputs, SessionStats, StationHealth,
    UsageRollupView, build_session_identity_cards_from_parts,
};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashboardSnapshot {
    pub refreshed_at_ms: u64,
    pub active: Vec<ActiveRequest>,
    pub recent: Vec<FinishedRequest>,
    #[serde(default)]
    pub session_cards: Vec<SessionIdentityCard>,
    #[serde(default)]
    pub global_station_override: Option<String>,
    #[serde(default)]
    pub global_route_target_override: Option<String>,
    #[serde(default)]
    pub session_model_overrides: HashMap<String, String>,
    #[serde(default)]
    pub session_station_overrides: HashMap<String, String>,
    #[serde(default)]
    pub session_route_target_overrides: HashMap<String, String>,
    #[serde(default)]
    pub session_effort_overrides: HashMap<String, String>,
    #[serde(default)]
    pub session_service_tier_overrides: HashMap<String, String>,
    pub session_stats: HashMap<String, SessionStats>,
    #[serde(default)]
    pub station_health: HashMap<String, StationHealth>,
    #[serde(default)]
    pub provider_balances: HashMap<String, Vec<ProviderBalanceSnapshot>>,
    pub health_checks: HashMap<String, HealthCheckStatus>,
    pub lb_view: HashMap<String, LbConfigView>,
    pub usage_rollup: UsageRollupView,
    pub stats_5m: WindowStats,
    pub stats_1h: WindowStats,
}

impl DashboardSnapshot {
    pub fn effective_global_station_override(&self) -> Option<&str> {
        self.global_station_override.as_deref()
    }

    pub fn effective_global_route_target_override(&self) -> Option<&str> {
        self.global_route_target_override.as_deref()
    }

    pub fn effective_station_health(&self) -> &HashMap<String, StationHealth> {
        &self.station_health
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiV1Snapshot {
    pub api_version: u32,
    pub service_name: String,
    pub runtime_loaded_at_ms: Option<u64>,
    pub runtime_source_mtime_ms: Option<u64>,
    #[serde(default)]
    pub stations: Vec<StationOption>,
    #[serde(default)]
    pub configured_active_station: Option<String>,
    #[serde(default)]
    pub effective_active_station: Option<String>,
    pub default_profile: Option<String>,
    #[serde(default)]
    pub profiles: Vec<ControlProfileOption>,
    pub snapshot: DashboardSnapshot,
}

fn now_ms() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_millis() as u64)
        .unwrap_or(0)
}

pub async fn build_dashboard_snapshot(
    state: &ProxyState,
    service_name: &str,
    recent_limit: usize,
    stats_days: usize,
) -> DashboardSnapshot {
    let now = now_ms();
    let recent_limit = recent_limit.clamp(1, 2_000);
    let recent_for_stats = recent_limit.max(2_000);

    let (
        active,
        mut recent_all,
        global_station_override,
        global_route_target_override,
        session_model,
        session_cfg,
        session_route_target,
        session_effort,
        session_service_tier,
        session_bindings,
        session_route_affinities,
        session_stats,
        usage_rollup,
        station_health,
        provider_balances,
        health_checks,
        lb_view,
    ) = tokio::join!(
        state.list_active_requests(),
        state.list_recent_finished(recent_for_stats),
        state.get_global_station_override(),
        state.get_global_route_target_override(),
        state.list_session_model_overrides(),
        state.list_session_station_overrides(),
        state.list_session_route_target_overrides(),
        state.list_session_effort_overrides(),
        state.list_session_service_tier_overrides(),
        state.list_session_bindings(),
        state.list_session_route_affinities(),
        state.list_session_stats(),
        state.get_usage_rollup_view(service_name, 12, stats_days),
        state.get_station_health(service_name),
        state.get_provider_balance_view(service_name),
        state.list_health_checks(service_name),
        state.get_lb_view(),
    );

    let stats_5m = compute_window_stats(&recent_all, now, 5 * 60_000, |_| true);
    let stats_1h = compute_window_stats(&recent_all, now, 60 * 60_000, |_| true);
    let mut session_cards =
        build_session_identity_cards_from_parts(SessionIdentityCardBuildInputs {
            active: &active,
            recent: &recent_all,
            overrides: &session_effort,
            station_overrides: &session_cfg,
            model_overrides: &session_model,
            service_tier_overrides: &session_service_tier,
            bindings: &session_bindings,
            route_affinities: &session_route_affinities,
            global_station_override: global_station_override.as_deref(),
            stats: &session_stats,
        });
    state
        .enrich_session_identity_cards_with_cached_host_transcripts(&mut session_cards)
        .await;

    if recent_all.len() > recent_limit {
        recent_all.truncate(recent_limit);
    }

    DashboardSnapshot {
        refreshed_at_ms: now,
        active,
        recent: recent_all,
        session_cards,
        global_station_override,
        global_route_target_override,
        session_model_overrides: session_model,
        session_station_overrides: session_cfg,
        session_route_target_overrides: session_route_target,
        session_effort_overrides: session_effort,
        session_service_tier_overrides: session_service_tier,
        session_stats,
        station_health,
        provider_balances,
        health_checks,
        lb_view,
        usage_rollup,
        stats_5m,
        stats_1h,
    }
}