use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::sync::Arc;
use std::time::Instant;
use ratatui::prelude::{Color, Style};
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
use crate::config::ProxyConfig;
use crate::dashboard_core::WindowStats;
pub(in crate::tui) use crate::dashboard_core::window_stats::compute_window_stats;
use crate::pricing::{ModelPriceCatalogSnapshot, UsdAmount};
use crate::state::{
BalanceSnapshotStatus, FinishedRequest, HealthCheckStatus, LbConfigView,
ProviderBalanceSnapshot, ProxyState, ResolvedRouteValue, RouteDecisionProvenance,
SessionIdentityCard, SessionObservationScope, SessionRouteAffinity, StationHealth,
UsageRollupView,
};
use crate::tui::Language;
use crate::tui::i18n;
use crate::usage::UsageMetrics;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct UpstreamSummary {
pub base_url: String,
pub provider_id: Option<String>,
pub auth: String,
pub tags: Vec<(String, String)>,
pub supported_models: Vec<String>,
pub model_mapping: Vec<(String, String)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ProviderOption {
pub name: String,
pub alias: Option<String>,
pub enabled: bool,
pub level: u8,
pub active: bool,
pub upstreams: Vec<UpstreamSummary>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, PartialEq, Eq, Default)]
pub(in crate::tui) struct RoutingProviderRef {
pub(in crate::tui) name: String,
#[serde(default)]
pub(in crate::tui) alias: Option<String>,
#[serde(default)]
pub(in crate::tui) enabled: bool,
#[serde(default)]
pub(in crate::tui) tags: BTreeMap<String, String>,
}
fn default_tui_routing_policy() -> crate::config::RoutingPolicyV4 {
crate::config::RoutingPolicyV4::OrderedFailover
}
fn default_tui_routing_on_exhausted() -> crate::config::RoutingExhaustedActionV4 {
crate::config::RoutingExhaustedActionV4::Continue
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
pub(in crate::tui) struct RoutingSpecView {
#[serde(default = "default_tui_routing_entry")]
pub(in crate::tui) entry: String,
#[serde(default)]
pub(in crate::tui) routes: BTreeMap<String, crate::config::RoutingNodeV4>,
#[serde(default = "default_tui_routing_policy")]
pub(in crate::tui) policy: crate::config::RoutingPolicyV4,
#[serde(default)]
pub(in crate::tui) order: Vec<String>,
#[serde(default)]
pub(in crate::tui) target: Option<String>,
#[serde(default)]
pub(in crate::tui) prefer_tags: Vec<BTreeMap<String, String>>,
#[serde(default)]
pub(in crate::tui) chain: Vec<String>,
#[serde(default)]
pub(in crate::tui) pools: BTreeMap<String, crate::config::RoutingPoolV4>,
#[serde(default = "default_tui_routing_on_exhausted")]
pub(in crate::tui) on_exhausted: crate::config::RoutingExhaustedActionV4,
#[serde(default = "default_tui_routing_policy")]
pub(in crate::tui) entry_strategy: crate::config::RoutingPolicyV4,
#[serde(default)]
pub(in crate::tui) expanded_order: Vec<String>,
#[serde(default)]
pub(in crate::tui) entry_target: Option<String>,
#[serde(default)]
pub(in crate::tui) providers: Vec<RoutingProviderRef>,
}
impl From<crate::config::PersistedRoutingProviderRef> for RoutingProviderRef {
fn from(provider: crate::config::PersistedRoutingProviderRef) -> Self {
Self {
name: provider.name,
alias: provider.alias,
enabled: provider.enabled,
tags: provider.tags,
}
}
}
impl From<crate::config::PersistedRoutingSpec> for RoutingSpecView {
fn from(spec: crate::config::PersistedRoutingSpec) -> Self {
Self {
entry: spec.entry,
routes: spec.routes,
policy: spec.policy,
order: spec.order,
target: spec.target,
prefer_tags: spec.prefer_tags,
chain: Vec::new(),
pools: BTreeMap::new(),
on_exhausted: spec.on_exhausted,
entry_strategy: spec.entry_strategy,
expanded_order: spec.expanded_order,
entry_target: spec.entry_target,
providers: spec.providers.into_iter().map(Into::into).collect(),
}
}
}
fn default_tui_routing_entry() -> String {
"main".to_string()
}
pub(in crate::tui) fn routing_provider_names(spec: &RoutingSpecView) -> Vec<String> {
let mut names = if spec.expanded_order.is_empty() {
spec.graph_provider_names()
} else {
spec.expanded_order.clone()
};
for provider in &spec.providers {
if !names.iter().any(|name| name == &provider.name) {
names.push(provider.name.clone());
}
}
names
}
impl RoutingSpecView {
pub(in crate::tui) fn entry_node(&self) -> Option<&crate::config::RoutingNodeV4> {
self.routes.get(self.entry.as_str())
}
pub(in crate::tui) fn entry_node_mut(&mut self) -> &mut crate::config::RoutingNodeV4 {
self.routes.entry(self.entry.clone()).or_default()
}
pub(in crate::tui) fn sync_entry_compat_from_graph(&mut self) {
if let Some(node) = self.entry_node().cloned() {
self.policy = node.strategy;
self.order = node.children;
self.target = node.target;
self.prefer_tags = node.prefer_tags;
self.on_exhausted = node.on_exhausted;
}
}
pub(in crate::tui) fn graph_provider_names(&self) -> Vec<String> {
let mut names = Vec::new();
let mut seen = BTreeSet::new();
self.push_route_leaves(self.entry.as_str(), &mut seen, &mut names);
if names.is_empty() {
names = routing_leaf_provider_names(self);
}
names
}
fn push_route_leaves(
&self,
route_or_provider: &str,
seen_routes: &mut BTreeSet<String>,
out: &mut Vec<String>,
) {
if self
.providers
.iter()
.any(|provider| provider.name == route_or_provider)
{
if !out.iter().any(|name| name == route_or_provider) {
out.push(route_or_provider.to_string());
}
return;
}
let Some(node) = self.routes.get(route_or_provider) else {
return;
};
if !seen_routes.insert(route_or_provider.to_string()) {
return;
}
if matches!(node.strategy, crate::config::RoutingPolicyV4::ManualSticky) {
if let Some(target) = node
.target
.as_deref()
.or_else(|| node.children.first().map(String::as_str))
{
self.push_route_leaves(target, seen_routes, out);
}
} else {
for child in &node.children {
self.push_route_leaves(child, seen_routes, out);
}
}
seen_routes.remove(route_or_provider);
}
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
pub(in crate::tui) struct RoutingSpecUpsertView {
pub(in crate::tui) entry: String,
#[serde(default)]
pub(in crate::tui) routes: BTreeMap<String, crate::config::RoutingNodeV4>,
#[serde(default = "default_tui_routing_policy")]
pub(in crate::tui) policy: crate::config::RoutingPolicyV4,
#[serde(default)]
pub(in crate::tui) order: Vec<String>,
#[serde(default)]
pub(in crate::tui) target: Option<String>,
#[serde(default)]
pub(in crate::tui) prefer_tags: Vec<BTreeMap<String, String>>,
#[serde(default = "default_tui_routing_on_exhausted")]
pub(in crate::tui) on_exhausted: crate::config::RoutingExhaustedActionV4,
}
impl From<&RoutingSpecView> for RoutingSpecUpsertView {
fn from(spec: &RoutingSpecView) -> Self {
Self {
entry: spec.entry.clone(),
routes: spec.routes.clone(),
policy: spec.policy,
order: spec.order.clone(),
target: spec.target.clone(),
prefer_tags: spec.prefer_tags.clone(),
on_exhausted: spec.on_exhausted,
}
}
}
impl From<RoutingSpecUpsertView> for crate::proxy::PersistedRoutingUpsertRequest {
fn from(spec: RoutingSpecUpsertView) -> Self {
Self {
entry: Some(spec.entry),
affinity_policy: None,
fallback_ttl_ms: None,
reprobe_preferred_after_ms: None,
routes: Some(spec.routes),
policy: Some(spec.policy),
order: spec.order,
target: spec.target,
prefer_tags: Some(spec.prefer_tags),
chain: Vec::new(),
pools: BTreeMap::new(),
on_exhausted: spec.on_exhausted,
}
}
}
pub(in crate::tui) fn routing_leaf_provider_names(spec: &RoutingSpecView) -> Vec<String> {
let mut names = if spec.order.is_empty() {
spec.providers
.iter()
.map(|provider| provider.name.clone())
.collect::<Vec<_>>()
} else {
spec.order.clone()
};
for provider in &spec.providers {
if !names.iter().any(|name| name == &provider.name) {
names.push(provider.name.clone());
}
}
names
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(in crate::tui) struct SessionRow {
pub(in crate::tui) session_id: Option<String>,
pub(in crate::tui) observation_scope: SessionObservationScope,
pub(in crate::tui) host_local_transcript_path: Option<String>,
pub(in crate::tui) last_client_name: Option<String>,
pub(in crate::tui) last_client_addr: Option<String>,
pub(in crate::tui) cwd: Option<String>,
pub(in crate::tui) active_count: usize,
pub(in crate::tui) active_started_at_ms_min: Option<u64>,
pub(in crate::tui) active_last_method: Option<String>,
pub(in crate::tui) active_last_path: Option<String>,
pub(in crate::tui) last_status: Option<u16>,
pub(in crate::tui) last_duration_ms: Option<u64>,
pub(in crate::tui) last_ended_at_ms: Option<u64>,
pub(in crate::tui) last_model: Option<String>,
pub(in crate::tui) last_reasoning_effort: Option<String>,
pub(in crate::tui) last_service_tier: Option<String>,
pub(in crate::tui) last_provider_id: Option<String>,
pub(in crate::tui) last_station_name: Option<String>,
pub(in crate::tui) last_upstream_base_url: Option<String>,
pub(in crate::tui) last_usage: Option<UsageMetrics>,
pub(in crate::tui) total_usage: Option<UsageMetrics>,
pub(in crate::tui) turns_total: Option<u64>,
pub(in crate::tui) turns_with_usage: Option<u64>,
pub(in crate::tui) binding_profile_name: Option<String>,
pub(in crate::tui) binding_continuity_mode: Option<crate::state::SessionContinuityMode>,
pub(in crate::tui) last_route_decision: Option<RouteDecisionProvenance>,
pub(in crate::tui) route_affinity: Option<SessionRouteAffinity>,
pub(in crate::tui) effective_model: Option<ResolvedRouteValue>,
pub(in crate::tui) effective_reasoning_effort: Option<ResolvedRouteValue>,
pub(in crate::tui) effective_service_tier: Option<ResolvedRouteValue>,
pub(in crate::tui) effective_station: Option<ResolvedRouteValue>,
pub(in crate::tui) effective_upstream_base_url: Option<ResolvedRouteValue>,
pub(in crate::tui) override_model: Option<String>,
pub(in crate::tui) override_effort: Option<String>,
pub(in crate::tui) override_station_name: Option<String>,
pub(in crate::tui) override_route_target: Option<String>,
pub(in crate::tui) override_service_tier: Option<String>,
}
#[derive(Debug, Clone)]
pub(in crate::tui) struct Snapshot {
pub(in crate::tui) rows: Vec<SessionRow>,
pub(in crate::tui) recent: Vec<FinishedRequest>,
pub(in crate::tui) model_overrides: HashMap<String, String>,
pub(in crate::tui) overrides: HashMap<String, String>,
pub(in crate::tui) station_overrides: HashMap<String, String>,
pub(in crate::tui) route_target_overrides: HashMap<String, String>,
pub(in crate::tui) service_tier_overrides: HashMap<String, String>,
pub(in crate::tui) global_station_override: Option<String>,
pub(in crate::tui) global_route_target_override: Option<String>,
pub(in crate::tui) station_meta_overrides: HashMap<String, (Option<bool>, Option<u8>)>,
pub(in crate::tui) usage_rollup: UsageRollupView,
pub(in crate::tui) provider_balances: HashMap<String, Vec<ProviderBalanceSnapshot>>,
pub(in crate::tui) station_health: HashMap<String, StationHealth>,
pub(in crate::tui) health_checks: HashMap<String, HealthCheckStatus>,
pub(in crate::tui) lb_view: HashMap<String, LbConfigView>,
pub(in crate::tui) stats_5m: WindowStats,
pub(in crate::tui) stats_1h: WindowStats,
pub(in crate::tui) pricing_catalog: ModelPriceCatalogSnapshot,
pub(in crate::tui) refreshed_at: Instant,
}
#[derive(Debug, Clone, Copy)]
pub(in crate::tui) struct Palette {
pub(in crate::tui) bg: Color,
pub(in crate::tui) panel: Color,
pub(in crate::tui) border: Color,
pub(in crate::tui) text: Color,
pub(in crate::tui) muted: Color,
pub(in crate::tui) accent: Color,
pub(in crate::tui) focus: Color,
pub(in crate::tui) good: Color,
pub(in crate::tui) warn: Color,
pub(in crate::tui) bad: Color,
}
impl Default for Palette {
fn default() -> Self {
Self {
bg: Color::Rgb(14, 17, 22),
panel: Color::Rgb(18, 22, 28),
border: Color::Rgb(54, 62, 74),
text: Color::Rgb(224, 228, 234),
muted: Color::Rgb(144, 154, 164),
accent: Color::Rgb(88, 166, 255),
focus: Color::Rgb(121, 192, 255),
good: Color::Rgb(63, 185, 80),
warn: Color::Rgb(210, 153, 34),
bad: Color::Rgb(248, 81, 73),
}
}
}
pub(in crate::tui) 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(in crate::tui) const CODEX_RECENT_WINDOWS: [(u64, &str); 6] = [
(30 * 60, "30m"),
(60 * 60, "1h"),
(3 * 60 * 60, "3h"),
(8 * 60 * 60, "8h"),
(12 * 60 * 60, "12h"),
(24 * 60 * 60, "24h"),
];
pub(in crate::tui) fn codex_recent_window_label(idx: usize) -> &'static str {
CODEX_RECENT_WINDOWS[idx.min(CODEX_RECENT_WINDOWS.len() - 1)].1
}
pub(in crate::tui) fn codex_recent_window_threshold_ms(now_ms: u64, idx: usize) -> u64 {
let secs = CODEX_RECENT_WINDOWS[idx.min(CODEX_RECENT_WINDOWS.len() - 1)].0;
now_ms.saturating_sub(secs.saturating_mul(1000))
}
pub(in crate::tui) fn basename(path: &str) -> &str {
let path = path.trim_end_matches(['/', '\\']);
let slash = path.rfind('/');
let backslash = path.rfind('\\');
let idx = match (slash, backslash) {
(Some(a), Some(b)) => Some(a.max(b)),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
};
if let Some(i) = idx {
&path[i.saturating_add(1)..]
} else {
path
}
}
pub(in crate::tui) fn shorten(s: &str, max: usize) -> String {
shorten_head(s, max)
}
pub(in crate::tui) fn shorten_middle(s: &str, max: usize) -> String {
if display_width(s) <= max {
return s.to_string();
}
if max == 0 {
return String::new();
}
if max == 1 {
return "…".to_string();
}
let remaining = max.saturating_sub(1);
let head_w = remaining / 2;
let tail_w = remaining.saturating_sub(head_w);
let head = prefix_by_width(s, head_w);
let tail = suffix_by_width(s, tail_w);
format!("{head}…{tail}")
}
fn shorten_head(s: &str, max: usize) -> String {
if display_width(s) <= max {
return s.to_string();
}
if max == 0 {
return String::new();
}
if max == 1 {
return "…".to_string();
}
let head = prefix_by_width(s, max.saturating_sub(1));
format!("{head}…")
}
fn display_width(s: &str) -> usize {
UnicodeWidthStr::width(s)
}
fn prefix_by_width(s: &str, max_width: usize) -> &str {
if max_width == 0 {
return "";
}
let mut width = 0usize;
let mut end = 0usize;
for (i, ch) in s.char_indices() {
let w = UnicodeWidthChar::width(ch).unwrap_or(0);
if width.saturating_add(w) > max_width {
break;
}
width = width.saturating_add(w);
end = i.saturating_add(ch.len_utf8());
}
&s[..end]
}
fn suffix_by_width(s: &str, max_width: usize) -> &str {
if max_width == 0 {
return "";
}
let mut width = 0usize;
let mut start = s.len();
for (i, ch) in s.char_indices().rev() {
let w = UnicodeWidthChar::width(ch).unwrap_or(0);
if width.saturating_add(w) > max_width {
break;
}
width = width.saturating_add(w);
start = i;
}
&s[start..]
}
pub(in crate::tui) fn short_sid(sid: &str, max: usize) -> String {
shorten_head(sid, max)
}
pub fn build_provider_options(
cfg: &crate::config::ProxyConfig,
service_name: &str,
) -> Vec<ProviderOption> {
let upstream_summary = |u: &crate::config::UpstreamConfig| -> UpstreamSummary {
let auth = if let Some(env) = u.auth.auth_token_env.as_deref()
&& !env.trim().is_empty()
{
format!("bearer env {env}")
} else if u
.auth
.auth_token
.as_deref()
.is_some_and(|s| !s.trim().is_empty())
{
"bearer inline".to_string()
} else if let Some(env) = u.auth.api_key_env.as_deref()
&& !env.trim().is_empty()
{
format!("x-api-key env {env}")
} else if u
.auth
.api_key
.as_deref()
.is_some_and(|s| !s.trim().is_empty())
{
"x-api-key inline".to_string()
} else {
"-".to_string()
};
let mut tags = u
.tags
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<Vec<_>>();
tags.sort_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
let mut supported_models = u.supported_models.keys().cloned().collect::<Vec<_>>();
supported_models.sort();
let mut model_mapping = u
.model_mapping
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<Vec<_>>();
model_mapping.sort_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(&b.1)));
UpstreamSummary {
base_url: u.base_url.clone(),
provider_id: u.tags.get("provider_id").cloned(),
auth,
tags,
supported_models,
model_mapping,
}
};
let mut providers: Vec<ProviderOption> = match service_name {
"claude" => cfg
.claude
.stations()
.iter()
.map(|(name, svc)| ProviderOption {
name: name.clone(),
alias: svc.alias.clone(),
enabled: svc.enabled,
level: svc.level.clamp(1, 10),
active: cfg.claude.active.as_deref() == Some(name.as_str()),
upstreams: svc.upstreams.iter().map(upstream_summary).collect(),
})
.collect(),
_ => cfg
.codex
.stations()
.iter()
.map(|(name, svc)| ProviderOption {
name: name.clone(),
alias: svc.alias.clone(),
enabled: svc.enabled,
level: svc.level.clamp(1, 10),
active: cfg.codex.active.as_deref() == Some(name.as_str()),
upstreams: svc.upstreams.iter().map(upstream_summary).collect(),
})
.collect(),
};
providers.sort_by(|a, b| a.level.cmp(&b.level).then_with(|| a.name.cmp(&b.name)));
providers
}
pub(in crate::tui) fn balance_status_style(p: Palette, status: BalanceSnapshotStatus) -> Style {
match status {
BalanceSnapshotStatus::Ok => Style::default().fg(p.good),
BalanceSnapshotStatus::Exhausted => Style::default().fg(p.bad),
BalanceSnapshotStatus::Error => Style::default().fg(p.warn),
BalanceSnapshotStatus::Stale => Style::default().fg(p.warn),
BalanceSnapshotStatus::Unknown => Style::default().fg(p.muted),
}
}
pub(in crate::tui) fn balance_snapshot_status_style(
p: Palette,
snapshot: &ProviderBalanceSnapshot,
) -> Style {
if snapshot.routing_ignored_exhaustion() {
Style::default().fg(p.warn)
} else {
balance_status_style(p, snapshot.status)
}
}
pub(in crate::tui) fn balance_amount_brief_lang(
snapshot: &ProviderBalanceSnapshot,
lang: Language,
) -> Option<String> {
if snapshot.unlimited_quota == Some(true) {
return Some(i18n::label(lang, "unlimited").to_string());
}
if let Some(total) = snapshot
.total_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
{
if let Some(quota) = quota_amount_brief(snapshot, lang) {
return Some(format!(
"{} {} | {}",
i18n::label(lang, "left"),
usd_brief(total),
quota
));
}
return Some(format!(
"{} {}",
i18n::label(lang, "left"),
usd_brief(total)
));
}
if let Some(amount) = quota_amount_brief(snapshot, lang) {
return Some(amount);
}
let subscription = snapshot
.subscription_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let paygo = snapshot
.paygo_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
if let (Some(sub), Some(paygo)) = (subscription, paygo) {
return Some(format!(
"{} {} {} + {} {}",
i18n::label(lang, "left"),
i18n::label(lang, "subscription"),
usd_brief(sub),
i18n::label(lang, "paygo"),
usd_brief(paygo)
));
}
if let Some(sub) = subscription {
return Some(format!(
"{} {} {}",
i18n::label(lang, "subscription"),
i18n::label(lang, "left"),
usd_brief(sub)
));
}
if let Some(paygo) = paygo {
return Some(format!(
"{} {} {}",
i18n::label(lang, "paygo"),
i18n::label(lang, "left"),
usd_brief(paygo)
));
}
match (
snapshot
.monthly_spent_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty()),
snapshot
.monthly_budget_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty()),
) {
(Some(spent), Some(budget)) => {
if let Some(left) = left_brief_from_budget_and_spent(budget, spent) {
Some(format!(
"{} {} / {} {}",
i18n::label(lang, "left"),
left,
i18n::label(lang, "budget"),
usd_brief(budget)
))
} else {
Some(format!(
"{} {} / {} {}",
i18n::label(lang, "budget"),
usd_brief(budget),
i18n::label(lang, "used"),
usd_brief(spent)
))
}
}
(Some(spent), None) => {
if snapshot.plan_name.is_none()
&& snapshot.quota_period.is_none()
&& snapshot.quota_remaining_usd.is_none()
&& snapshot.quota_limit_usd.is_none()
&& snapshot.quota_used_usd.is_none()
{
Some(format!(
"{} {}",
i18n::label(lang, "used"),
usd_brief(spent)
))
} else {
None
}
}
(None, Some(budget)) => Some(format!(
"{} {}",
i18n::label(lang, "budget"),
usd_brief(budget)
)),
(None, None) => snapshot
.total_used_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(|value| format!("{} {}", i18n::label(lang, "used"), usd_brief(value)))
.or_else(|| {
snapshot
.today_used_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(|value| {
format!("{} {}", i18n::label(lang, "today used"), usd_brief(value))
})
}),
}
}
fn quota_amount_brief(snapshot: &ProviderBalanceSnapshot, lang: Language) -> Option<String> {
let period = snapshot
.quota_period
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let remaining = snapshot
.quota_remaining_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let limit = snapshot
.quota_limit_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let used = snapshot
.quota_used_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
if remaining.is_none() && limit.is_none() && used.is_none() {
return None;
}
let quota_label = match period {
Some("quota") | None => i18n::label(lang, "quota").to_string(),
Some(period) => period.to_string(),
};
let amount = match (remaining, limit, used) {
(Some(remaining), Some(limit), _) => {
format!(
"{} {} / {}",
i18n::label(lang, "left"),
usd_brief(remaining),
usd_brief(limit)
)
}
(Some(remaining), None, Some(used)) => {
format!(
"{} {} / {} {}",
i18n::label(lang, "left"),
usd_brief(remaining),
i18n::label(lang, "used"),
usd_brief(used)
)
}
(Some(remaining), None, None) => {
format!("{} {}", i18n::label(lang, "left"), usd_brief(remaining))
}
(None, Some(limit), Some(used)) => {
format!(
"{} {} / {}",
i18n::label(lang, "used"),
usd_brief(used),
usd_brief(limit)
)
}
(None, Some(limit), None) => {
format!("{} {}", i18n::label(lang, "limit"), usd_brief(limit))
}
(None, None, Some(used)) => {
format!("{} {}", i18n::label(lang, "used"), usd_brief(used))
}
(None, None, None) => return None,
};
Some(format!("{quota_label} {amount}"))
}
fn balance_amount_terse_lang(snapshot: &ProviderBalanceSnapshot, lang: Language) -> Option<String> {
if snapshot.unlimited_quota == Some(true) {
return Some(i18n::label(lang, "unlimited").to_string());
}
let subscription = snapshot
.subscription_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let paygo = snapshot
.paygo_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let total = snapshot
.total_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
if let Some(total) = total {
return Some(usd_brief(total));
}
if let Some(amount) = quota_amount_terse(snapshot, lang) {
return Some(amount);
}
match (subscription, paygo) {
(Some(sub), Some(paygo)) => Some(format!(
"{} {} + {} {}",
i18n::label(lang, "subscription"),
usd_brief(sub),
i18n::label(lang, "paygo"),
usd_brief(paygo)
)),
(Some(sub), None) => Some(format!(
"{} {}",
i18n::label(lang, "subscription"),
usd_brief(sub)
)),
(None, Some(paygo)) => Some(format!(
"{} {}",
i18n::label(lang, "paygo"),
usd_brief(paygo)
)),
(None, None) => None,
}
}
fn balance_amount_tiny(snapshot: &ProviderBalanceSnapshot) -> Option<String> {
let total = snapshot
.total_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
if let Some(total) = total {
return Some(usd_brief(total));
}
if let Some(amount) = quota_amount_tiny(snapshot) {
return Some(amount);
}
let subscription = snapshot
.subscription_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let paygo = snapshot
.paygo_balance_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
match (subscription, paygo) {
(Some(sub), None) => Some(usd_brief(sub)),
(None, Some(paygo)) => Some(usd_brief(paygo)),
_ => None,
}
}
fn quota_amount_terse(snapshot: &ProviderBalanceSnapshot, lang: Language) -> Option<String> {
let period = snapshot
.quota_period
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let remaining = snapshot
.quota_remaining_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let limit = snapshot
.quota_limit_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
match (remaining, limit) {
(Some(remaining), Some(limit)) => {
let quota_label = match period {
Some("quota") | None => i18n::label(lang, "quota").to_string(),
Some(period) => period.to_string(),
};
Some(format!(
"{quota_label} {}/{}",
usd_brief(remaining),
usd_brief(limit)
))
}
_ => None,
}
}
fn quota_amount_tiny(snapshot: &ProviderBalanceSnapshot) -> Option<String> {
let remaining = snapshot
.quota_remaining_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
let limit = snapshot
.quota_limit_usd
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty());
match (remaining, limit) {
(Some(remaining), Some(limit)) => {
Some(format!("{}/{}", usd_brief(remaining), usd_brief(limit)))
}
_ => None,
}
}
fn usd_brief(raw: &str) -> String {
format!("${}", decimal_brief(raw))
}
fn left_brief_from_budget_and_spent(budget: &str, spent: &str) -> Option<String> {
let budget = UsdAmount::from_decimal_str(budget)?;
let spent = UsdAmount::from_decimal_str(spent)?;
Some(format!("${}", budget.saturating_sub(spent).format_usd()))
}
fn decimal_brief(raw: &str) -> String {
let raw = raw.trim();
let Ok(value) = raw.parse::<f64>() else {
return raw.to_string();
};
if !value.is_finite() {
return raw.to_string();
}
let decimals = if value.abs() >= 1.0 { 2 } else { 4 };
let mut out = format!("{value:.decimals$}");
if value.abs() < 1.0
&& let Some(dot) = out.find('.')
{
while out.ends_with('0') {
out.pop();
}
if out.len() == dot + 1 {
out.pop();
}
}
if out == "-0" { "0".to_string() } else { out }
}
fn balance_status_brief_lang(status: BalanceSnapshotStatus, lang: Language) -> &'static str {
match status {
BalanceSnapshotStatus::Ok => i18n::label(lang, "ok"),
BalanceSnapshotStatus::Exhausted => i18n::label(lang, "exh"),
BalanceSnapshotStatus::Stale => i18n::label(lang, "stale"),
BalanceSnapshotStatus::Error | BalanceSnapshotStatus::Unknown => {
i18n::label(lang, "unknown")
}
}
}
fn balance_snapshot_status_brief_lang(
snapshot: &ProviderBalanceSnapshot,
lang: Language,
) -> &'static str {
if snapshot.routing_ignored_exhaustion() {
i18n::label(lang, "lazy")
} else {
balance_status_brief_lang(snapshot.status, lang)
}
}
pub(in crate::tui) fn balance_status_label_lang(
status: BalanceSnapshotStatus,
lang: Language,
) -> &'static str {
match status {
BalanceSnapshotStatus::Ok => i18n::label(lang, "ok"),
BalanceSnapshotStatus::Exhausted => i18n::label(lang, "exhausted"),
BalanceSnapshotStatus::Stale => i18n::label(lang, "stale"),
BalanceSnapshotStatus::Error | BalanceSnapshotStatus::Unknown => {
i18n::label(lang, "unknown")
}
}
}
#[cfg(test)]
pub(in crate::tui) fn balance_snapshot_status_label(
snapshot: &ProviderBalanceSnapshot,
) -> &'static str {
balance_snapshot_status_label_lang(snapshot, Language::En)
}
pub(in crate::tui) fn balance_snapshot_status_label_lang(
snapshot: &ProviderBalanceSnapshot,
lang: Language,
) -> &'static str {
if snapshot.routing_ignored_exhaustion() {
i18n::label(lang, "lazy reset")
} else {
balance_status_label_lang(snapshot.status, lang)
}
}
#[cfg(test)]
pub(in crate::tui) fn provider_balance_compact(
snapshot: &ProviderBalanceSnapshot,
max_width: usize,
) -> String {
provider_balance_compact_lang(snapshot, max_width, Language::En)
}
pub(in crate::tui) fn provider_balance_compact_lang(
snapshot: &ProviderBalanceSnapshot,
max_width: usize,
lang: Language,
) -> String {
let status = (snapshot.status != BalanceSnapshotStatus::Ok)
.then(|| balance_snapshot_status_brief_lang(snapshot, lang).to_string());
let plan = snapshot
.plan_name
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToOwned::to_owned);
let amount = balance_amount_brief_lang(snapshot, lang);
let terse_amount = balance_amount_terse_lang(snapshot, lang);
let tiny_amount = balance_amount_tiny(snapshot);
let mut candidates = Vec::new();
let full = [status.as_deref(), plan.as_deref(), amount.as_deref()]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(" ");
if !full.is_empty() {
push_balance_candidate(&mut candidates, full);
}
if amount.is_some() {
let without_plan = [status.as_deref(), amount.as_deref()]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(" ");
if !without_plan.is_empty() {
push_balance_candidate(&mut candidates, without_plan);
}
}
if let (Some(status), Some(terse_amount)) = (status.as_deref(), terse_amount.as_deref()) {
push_balance_candidate(&mut candidates, format!("{status} {terse_amount}"));
}
if let Some(amount) = amount.clone() {
push_balance_candidate(&mut candidates, amount);
}
if let Some(terse_amount) = terse_amount.clone() {
push_balance_candidate(&mut candidates, terse_amount);
}
if let Some(tiny_amount) = tiny_amount.clone() {
push_balance_candidate(&mut candidates, tiny_amount);
}
if let Some(status) = status.clone() {
push_balance_candidate(&mut candidates, status);
}
if candidates.is_empty() {
push_balance_candidate(
&mut candidates,
balance_snapshot_status_brief_lang(snapshot, lang).to_string(),
);
}
if let Some(candidate) = candidates
.iter()
.find(|candidate| display_width(candidate) <= max_width)
{
return candidate.clone();
}
balance_atomic_fallback(snapshot, max_width, lang)
}
fn push_balance_candidate(candidates: &mut Vec<String>, candidate: String) {
if !candidate.is_empty() && !candidates.iter().any(|existing| existing == &candidate) {
candidates.push(candidate);
}
}
fn balance_snapshot_rank(snapshot: &ProviderBalanceSnapshot) -> u8 {
match snapshot.status {
BalanceSnapshotStatus::Ok => 0,
BalanceSnapshotStatus::Stale => 1,
BalanceSnapshotStatus::Exhausted if snapshot.routing_ignored_exhaustion() => 1,
BalanceSnapshotStatus::Unknown | BalanceSnapshotStatus::Error => 2,
BalanceSnapshotStatus::Exhausted => 3,
}
}
fn primary_balance_snapshot(
balances: &[ProviderBalanceSnapshot],
) -> Option<&ProviderBalanceSnapshot> {
balances.iter().min_by(|left, right| {
balance_snapshot_rank(left)
.cmp(&balance_snapshot_rank(right))
.then_with(|| left.upstream_index.cmp(&right.upstream_index))
.then_with(|| left.provider_id.cmp(&right.provider_id))
.then_with(|| right.fetched_at_ms.cmp(&left.fetched_at_ms))
})
}
pub(in crate::tui) fn station_primary_balance_snapshot<'a>(
provider_balances: &'a HashMap<String, Vec<ProviderBalanceSnapshot>>,
station_name: &str,
) -> Option<&'a ProviderBalanceSnapshot> {
provider_balances
.get(station_name)
.and_then(|balances| primary_balance_snapshot(balances))
}
#[cfg(test)]
pub(in crate::tui) fn station_balance_brief(
provider_balances: &HashMap<String, Vec<ProviderBalanceSnapshot>>,
station_name: &str,
max_width: usize,
) -> String {
station_balance_brief_lang(provider_balances, station_name, max_width, Language::En)
}
pub(in crate::tui) fn station_balance_brief_lang(
provider_balances: &HashMap<String, Vec<ProviderBalanceSnapshot>>,
station_name: &str,
max_width: usize,
lang: Language,
) -> String {
let Some(balances) = provider_balances.get(station_name) else {
return "-".to_string();
};
if balances.is_empty() {
return "-".to_string();
}
if balances.len() == 1 {
return provider_balance_compact_lang(&balances[0], max_width, lang);
}
let total = balances.len();
let ok = balances
.iter()
.filter(|snapshot| snapshot.status == BalanceSnapshotStatus::Ok)
.count();
let stale = balances
.iter()
.filter(|snapshot| snapshot.status == BalanceSnapshotStatus::Stale)
.count();
let exhausted = balances
.iter()
.filter(|snapshot| {
snapshot.status == BalanceSnapshotStatus::Exhausted
&& !snapshot.routing_ignored_exhaustion()
})
.count();
let lazy_exhausted = balances
.iter()
.filter(|snapshot| snapshot.routing_ignored_exhaustion())
.count();
let error = balances
.iter()
.filter(|snapshot| snapshot.status == BalanceSnapshotStatus::Error)
.count();
let unknown = balances
.iter()
.filter(|snapshot| snapshot.status == BalanceSnapshotStatus::Unknown)
.count();
let displayed_unknown = unknown + error;
let primary = primary_balance_snapshot(balances);
let primary_amount = primary.and_then(|snapshot| balance_amount_brief_lang(snapshot, lang));
let primary_terse_amount =
primary.and_then(|snapshot| balance_amount_terse_lang(snapshot, lang));
let primary_tiny_amount = primary.and_then(balance_amount_tiny);
let mut parts = Vec::new();
let mut amount_index = None;
if primary_amount.is_none() || ok == 0 {
if ok > 0 {
parts.push(format!("{} {ok}/{total}", i18n::label(lang, "ok")));
} else if stale > 0 {
parts.push(format!("{} {stale}/{total}", i18n::label(lang, "stale")));
} else if displayed_unknown > 0 {
parts.push(format!(
"{} {displayed_unknown}/{total}",
i18n::label(lang, "unknown")
));
} else if lazy_exhausted > 0 {
parts.push(format!(
"{} {lazy_exhausted}/{total}",
i18n::label(lang, "lazy")
));
} else if exhausted > 0 {
parts.push(format!("{} {exhausted}/{total}", i18n::label(lang, "exh")));
}
}
if let Some(amount) = primary_amount {
amount_index = Some(parts.len());
parts.push(amount);
}
if exhausted > 0 && ok > 0 {
parts.push(format!("{} {exhausted}", i18n::label(lang, "exh")));
}
if lazy_exhausted > 0 && ok > 0 {
parts.push(format!("{} {lazy_exhausted}", i18n::label(lang, "lazy")));
}
if error > 0 && (ok > 0 || stale > 0 || unknown > 0 || exhausted > 0 || lazy_exhausted > 0) {
parts.push(format!("{} {error}", i18n::label(lang, "unknown")));
}
if parts.is_empty() {
"-".to_string()
} else {
let fallback_label = if ok > 0 {
i18n::label(lang, "ok").to_string()
} else if stale > 0 {
format!("{} {stale}/{total}", i18n::label(lang, "stale"))
} else if displayed_unknown > 0 {
format!(
"{} {displayed_unknown}/{total}",
i18n::label(lang, "unknown")
)
} else if lazy_exhausted > 0 {
format!("{} {lazy_exhausted}/{total}", i18n::label(lang, "lazy"))
} else if exhausted > 0 {
format!("{} {exhausted}/{total}", i18n::label(lang, "exh"))
} else {
"-".to_string()
};
compact_balance_parts(
&parts,
amount_index,
primary_terse_amount.as_deref(),
primary_tiny_amount.as_deref(),
max_width,
&fallback_label,
)
}
}
fn balance_atomic_fallback(
snapshot: &ProviderBalanceSnapshot,
max_width: usize,
lang: Language,
) -> String {
let label = balance_snapshot_status_brief_lang(snapshot, lang);
if display_width(label) <= max_width {
return label.to_string();
}
shorten_middle(label, max_width)
}
fn compact_balance_parts(
parts: &[String],
amount_index: Option<usize>,
terse_amount: Option<&str>,
tiny_amount: Option<&str>,
max_width: usize,
fallback_label: &str,
) -> String {
let full = parts.join(" ");
if display_width(&full) <= max_width {
return full;
}
if let Some(amount_index) = amount_index {
let mut candidate = parts[amount_index].clone();
for part in parts.iter().skip(amount_index.saturating_add(1)) {
let next = format!("{candidate} {part}");
if display_width(&next) <= max_width {
candidate = next;
}
}
for part in parts[..amount_index].iter().rev() {
let next = format!("{part} {candidate}");
if display_width(&next) <= max_width {
candidate = next;
}
}
if display_width(&candidate) <= max_width {
return candidate;
}
if let Some(terse_amount) = terse_amount
&& display_width(terse_amount) <= max_width
{
return terse_amount.to_string();
}
if let Some(tiny_amount) = tiny_amount
&& display_width(tiny_amount) <= max_width
{
return tiny_amount.to_string();
}
}
let non_amount = parts
.iter()
.enumerate()
.filter(|(idx, _)| Some(*idx) != amount_index)
.map(|(_, part)| part.as_str())
.find(|part| display_width(part) <= max_width);
if let Some(part) = non_amount {
return part.to_string();
}
if display_width(fallback_label) <= max_width {
return fallback_label.to_string();
}
shorten_middle(fallback_label, max_width)
}
#[cfg(test)]
fn row_station_candidates(row: &SessionRow) -> impl Iterator<Item = &str> {
[
row.last_station_name.as_deref(),
row.effective_station
.as_ref()
.map(|value| value.value.as_str()),
row.override_station_name.as_deref(),
row.override_route_target.as_deref(),
]
.into_iter()
.flatten()
.map(str::trim)
.filter(|value| !value.is_empty() && *value != "-")
}
fn balance_by_provider_id<'a>(
provider_balances: &'a HashMap<String, Vec<ProviderBalanceSnapshot>>,
provider_id: &str,
) -> Option<(&'a str, &'a ProviderBalanceSnapshot)> {
let mut matches = provider_balances
.iter()
.flat_map(|(station_name, balances)| {
balances
.iter()
.filter(move |snapshot| {
snapshot.provider_id == provider_id
|| (snapshot.provider_id.trim().is_empty() && station_name == provider_id)
})
.map(move |snapshot| (station_name.as_str(), snapshot))
})
.collect::<Vec<_>>();
if matches.is_empty() {
return None;
}
matches.sort_by(|(_, left), (_, right)| {
balance_snapshot_rank(left)
.cmp(&balance_snapshot_rank(right))
.then_with(|| left.upstream_index.cmp(&right.upstream_index))
.then_with(|| right.fetched_at_ms.cmp(&left.fetched_at_ms))
});
matches.into_iter().next()
}
#[cfg(test)]
pub(in crate::tui) fn session_balance_brief(
row: &SessionRow,
provider_balances: &HashMap<String, Vec<ProviderBalanceSnapshot>>,
max_width: usize,
) -> Option<String> {
session_balance_brief_lang(row, provider_balances, max_width, Language::En)
}
#[cfg(test)]
fn session_balance_brief_lang(
row: &SessionRow,
provider_balances: &HashMap<String, Vec<ProviderBalanceSnapshot>>,
max_width: usize,
lang: Language,
) -> Option<String> {
for station_name in row_station_candidates(row) {
if provider_balances.contains_key(station_name) {
return Some(station_balance_brief_lang(
provider_balances,
station_name,
max_width,
lang,
));
}
}
row.last_provider_id
.as_deref()
.map(str::trim)
.filter(|provider_id| !provider_id.is_empty())
.and_then(|provider_id| balance_by_provider_id(provider_balances, provider_id))
.map(|(station_name, snapshot)| {
shorten_middle(
&format!(
"{} {}",
shorten_middle(station_name, 18),
provider_balance_compact_lang(snapshot, max_width, lang)
),
max_width,
)
})
}
pub(in crate::tui) fn session_observed_provider_balance_brief_lang(
row: &SessionRow,
provider_balances: &HashMap<String, Vec<ProviderBalanceSnapshot>>,
max_width: usize,
lang: Language,
) -> Option<String> {
let provider_id = row
.last_provider_id
.as_deref()
.map(str::trim)
.filter(|provider_id| !provider_id.is_empty() && *provider_id != "-")?;
balance_by_provider_id(provider_balances, provider_id)
.map(|(_, snapshot)| provider_balance_compact_lang(snapshot, max_width, lang))
}
pub(in crate::tui) fn session_observed_provider_balance_snapshot<'a>(
row: &SessionRow,
provider_balances: &'a HashMap<String, Vec<ProviderBalanceSnapshot>>,
) -> Option<&'a ProviderBalanceSnapshot> {
let provider_id = row
.last_provider_id
.as_deref()
.map(str::trim)
.filter(|provider_id| !provider_id.is_empty() && *provider_id != "-")?;
balance_by_provider_id(provider_balances, provider_id).map(|(_, snapshot)| snapshot)
}
pub(in crate::tui) fn provider_tags_brief(
provider: &ProviderOption,
max_width: usize,
) -> Option<String> {
let mut tags = provider
.upstreams
.iter()
.flat_map(|upstream| upstream.tags.iter())
.filter(|(key, value)| {
!value.trim().is_empty()
&& key.as_str() != "provider_id"
&& key.as_str() != "source"
&& key.as_str() != "requires_openai_auth"
})
.map(|(key, value)| format!("{key}={value}"))
.collect::<Vec<_>>();
tags.sort();
tags.dedup();
if tags.is_empty() {
tags = provider
.upstreams
.iter()
.filter_map(|upstream| upstream.provider_id.as_deref())
.map(|provider_id| format!("provider_id={provider_id}"))
.collect::<Vec<_>>();
tags.sort();
tags.dedup();
}
if tags.is_empty() {
None
} else {
Some(shorten_middle(&tags.join(" "), max_width))
}
}
fn session_sort_key(row: &SessionRow) -> u64 {
row.last_ended_at_ms
.unwrap_or(0)
.max(row.active_started_at_ms_min.unwrap_or(0))
}
pub(in crate::tui) fn format_age(now_ms: u64, ts_ms: Option<u64>) -> String {
let Some(ts) = ts_ms else {
return "-".to_string();
};
if now_ms <= ts {
return "0s".to_string();
}
let mut secs = (now_ms - ts) / 1000;
let days = secs / 86400;
secs %= 86400;
let hours = secs / 3600;
secs %= 3600;
let mins = secs / 60;
secs %= 60;
if days > 0 {
format!("{days}d{hours}h")
} else if hours > 0 {
format!("{hours}h{mins}m")
} else if mins > 0 {
format!("{mins}m{secs}s")
} else {
format!("{secs}s")
}
}
pub(in crate::tui) fn duration_short(ms: u64) -> String {
if ms < 1_000 {
format!("{ms}ms")
} else if ms < 10_000 {
let mut out = format!("{:.1}s", ms as f64 / 1_000.0);
if out.ends_with(".0s") {
out.replace_range(out.len() - 3..out.len() - 1, "");
}
out
} else if ms < 60_000 {
format!("{}s", ms / 1_000)
} else if ms < 3_600_000 {
let secs = ms / 1_000;
format!("{}m{}s", secs / 60, secs % 60)
} else {
let secs = ms / 1_000;
let mins = (secs % 3_600) / 60;
format!("{}h{}m", secs / 3_600, mins)
}
}
pub(in crate::tui) fn tokens_short(n: i64) -> String {
let n = n.max(0) as f64;
if n >= 1_000_000.0 {
format!("{:.1}m", n / 1_000_000.0)
} else if n >= 1_000.0 {
format!("{:.1}k", n / 1_000.0)
} else {
format!("{:.0}", n)
}
}
pub(in crate::tui) fn usage_line_lang(usage: &UsageMetrics, lang: Language) -> String {
let mut line = format!(
"{}: {}/{}/{}/{}",
i18n::label(lang, "tok in/out/rsn/ttl"),
tokens_short(usage.input_tokens),
tokens_short(usage.output_tokens),
tokens_short(usage.reasoning_output_tokens_total()),
tokens_short(usage.total_tokens)
);
if usage.has_cache_tokens() {
line.push_str(&format!(
" {}: {}/{}",
i18n::label(lang, "cache read/create"),
tokens_short(usage.cache_read_tokens_total()),
tokens_short(usage.cache_creation_tokens_total())
));
}
line
}
pub(in crate::tui) fn request_cache_hit_rate_label(request: &FinishedRequest) -> String {
request
.cache_hit_rate()
.map(|rate| format!("{:.1}%", rate * 100.0))
.unwrap_or_else(|| "-".to_string())
}
pub(in crate::tui) fn status_style(p: Palette, status: Option<u16>) -> Style {
match status {
Some(s) if (200..300).contains(&s) => Style::default().fg(p.good),
Some(s) if (300..400).contains(&s) => Style::default().fg(p.accent),
Some(s) if (400..500).contains(&s) => Style::default().fg(p.warn),
Some(_) => Style::default().fg(p.bad),
None => Style::default().fg(p.muted),
}
}
fn build_session_rows_from_cards(cards: &[SessionIdentityCard]) -> Vec<SessionRow> {
let mut rows = cards
.iter()
.filter_map(|card| {
let session_id = card.session_id.clone()?;
Some(SessionRow {
session_id: Some(session_id),
observation_scope: card.observation_scope,
host_local_transcript_path: card.host_local_transcript_path.clone(),
last_client_name: card.last_client_name.clone(),
last_client_addr: card.last_client_addr.clone(),
cwd: card.cwd.clone(),
active_count: card.active_count as usize,
active_started_at_ms_min: card.active_started_at_ms_min,
active_last_method: None,
active_last_path: None,
last_status: card.last_status,
last_duration_ms: card.last_duration_ms,
last_ended_at_ms: card.last_ended_at_ms,
last_model: card.last_model.clone(),
last_reasoning_effort: card.last_reasoning_effort.clone(),
last_service_tier: card.last_service_tier.clone(),
last_provider_id: card.last_provider_id.clone(),
last_station_name: card.last_station_name.clone(),
last_upstream_base_url: card.last_upstream_base_url.clone(),
last_usage: card.last_usage.clone(),
total_usage: card.total_usage.clone(),
turns_total: card.turns_total,
turns_with_usage: card.turns_with_usage,
binding_profile_name: card.binding_profile_name.clone(),
binding_continuity_mode: card.binding_continuity_mode,
last_route_decision: card.last_route_decision.clone(),
route_affinity: card.route_affinity.clone(),
effective_model: card.effective_model.clone(),
effective_reasoning_effort: card.effective_reasoning_effort.clone(),
effective_service_tier: card.effective_service_tier.clone(),
effective_station: card.effective_station.clone(),
effective_upstream_base_url: card.effective_upstream_base_url.clone(),
override_model: card.override_model.clone(),
override_effort: card.override_effort.clone(),
override_station_name: card.override_station_name.clone(),
override_route_target: None,
override_service_tier: card.override_service_tier.clone(),
})
})
.collect::<Vec<_>>();
rows.sort_by_key(|r| std::cmp::Reverse(session_sort_key(r)));
rows
}
pub(in crate::tui) fn session_row_has_any_override(row: &SessionRow) -> bool {
row.override_model.is_some()
|| row.override_effort.is_some()
|| row.override_station_name.is_some()
|| row.override_route_target.is_some()
|| row.override_service_tier.is_some()
}
pub(in crate::tui) fn format_observed_client_identity(
client_name: Option<&str>,
client_addr: Option<&str>,
) -> Option<String> {
match (
client_name.map(str::trim).filter(|value| !value.is_empty()),
client_addr.map(str::trim).filter(|value| !value.is_empty()),
) {
(Some(name), Some(addr)) => Some(format!("{name} @ {addr}")),
(Some(name), None) => Some(name.to_string()),
(None, Some(addr)) => Some(addr.to_string()),
(None, None) => None,
}
}
pub(in crate::tui) fn session_observation_scope_label_lang(
scope: SessionObservationScope,
lang: Language,
) -> &'static str {
match scope {
SessionObservationScope::ObservedOnly => i18n::label(lang, "observed only"),
SessionObservationScope::HostLocalEnriched => i18n::label(lang, "host-local enriched"),
}
}
pub(in crate::tui) fn session_transcript_host_status_lang(
row: &SessionRow,
lang: Language,
) -> String {
if row.host_local_transcript_path.is_some() {
i18n::label(lang, "linked under ~/.codex/sessions").to_string()
} else {
i18n::label(lang, "no host-local transcript detected").to_string()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(in crate::tui) struct SessionControlPosture {
pub(in crate::tui) headline: String,
pub(in crate::tui) detail: String,
pub(in crate::tui) color: Color,
}
pub(in crate::tui) fn session_override_fields(row: &SessionRow) -> Vec<&'static str> {
let mut fields = Vec::new();
if row.override_model.is_some() {
fields.push("model");
}
if row.override_effort.is_some() {
fields.push("effort");
}
if row.override_station_name.is_some() {
fields.push("station");
}
if row.override_route_target.is_some() {
fields.push("route target");
}
if row.override_service_tier.is_some() {
fields.push("service_tier");
}
fields
}
#[cfg(test)]
pub(in crate::tui) fn session_control_posture(
row: &SessionRow,
global_station: Option<&str>,
global_route_target: Option<&str>,
route_graph_routing: bool,
) -> SessionControlPosture {
session_control_posture_lang(
row,
global_station,
global_route_target,
route_graph_routing,
Language::En,
)
}
pub(in crate::tui) fn session_control_posture_lang(
row: &SessionRow,
global_station: Option<&str>,
global_route_target: Option<&str>,
route_graph_routing: bool,
lang: Language,
) -> SessionControlPosture {
let override_fields = session_override_fields(row);
let override_fields_label = || {
override_fields
.iter()
.map(|field| i18n::label(lang, field))
.collect::<Vec<_>>()
.join(", ")
};
if let Some(profile_name) = row.binding_profile_name.as_deref() {
if override_fields.is_empty() {
let mode = row
.binding_continuity_mode
.map(|mode| format!("{mode:?}").to_ascii_lowercase())
.unwrap_or_else(|| "default_profile".to_string());
return SessionControlPosture {
headline: match lang {
Language::Zh => format!("绑定到 profile {profile_name}({mode})"),
Language::En => format!("bound to profile {profile_name} ({mode})"),
},
detail: i18n::label(
lang,
"This session keeps its stored binding until another profile or override rewrites it.",
)
.to_string(),
color: Color::Rgb(63, 185, 80),
};
}
return SessionControlPosture {
headline: match lang {
Language::Zh => format!("profile {profile_name} 存在会话覆盖"),
Language::En => format!("profile {profile_name} with session overrides"),
},
detail: format!(
"{} {}",
i18n::label(
lang,
"Session overrides currently take priority over the bound profile:",
),
override_fields_label()
),
color: Color::Rgb(88, 166, 255),
};
}
if !override_fields.is_empty() {
return SessionControlPosture {
headline: i18n::label(lang, "session-controlled route").to_string(),
detail: format!(
"{} {}",
i18n::label(lang, "This session is currently pinned by overrides on:"),
override_fields_label()
),
color: Color::Rgb(88, 166, 255),
};
}
if route_graph_routing
&& let Some(route_target) = global_route_target.filter(|target| !target.trim().is_empty())
{
return SessionControlPosture {
headline: match lang {
Language::Zh => format!("无绑定;全局路由目标 {route_target} 仍会影响路由"),
Language::En => {
format!(
"no binding; global route target {route_target} may still influence routing"
)
}
},
detail: i18n::label(
lang,
"Without a stored profile or session override, route graph defaults and runtime/global routing explain the effective route.",
)
.to_string(),
color: Color::Rgb(210, 153, 34),
};
}
if let Some(station) = global_station.filter(|station| !station.trim().is_empty()) {
return SessionControlPosture {
headline: match lang {
Language::Zh => format!("无绑定;全局站点 {station} 仍可能影响回退"),
Language::En => {
format!("no binding; global station {station} may still influence fallback")
}
},
detail: i18n::label(
lang,
"Without a stored profile or session override, runtime/global routing explains the effective route.",
)
.to_string(),
color: Color::Rgb(210, 153, 34),
};
}
SessionControlPosture {
headline: i18n::label(lang, "no stored binding or session override").to_string(),
detail: i18n::label(
lang,
if route_graph_routing {
"Effective route comes from request payloads, route graph defaults, route target overrides, and runtime fallback."
} else {
"Effective route comes from request payloads, station defaults, and runtime fallback."
},
)
.to_string(),
color: Color::Rgb(144, 154, 164),
}
}
pub(in crate::tui) async fn refresh_snapshot(
state: &ProxyState,
cfg: Arc<ProxyConfig>,
service_name: &str,
stats_days: usize,
) -> Snapshot {
let (mut snap, config_meta) = tokio::join!(
crate::dashboard_core::build_dashboard_snapshot(state, service_name, 2_000, stats_days),
state.get_station_meta_overrides(service_name),
);
let mgr = match service_name {
"claude" => &cfg.claude,
_ => &cfg.codex,
};
crate::state::enrich_session_identity_cards_with_runtime(&mut snap.session_cards, mgr);
let global_station_override = snap.effective_global_station_override().map(str::to_owned);
let global_route_target_override = snap
.effective_global_route_target_override()
.map(str::to_owned);
let station_health = snap.effective_station_health().clone();
let mut rows = build_session_rows_from_cards(&snap.session_cards);
for row in &mut rows {
if let Some(session_id) = row.session_id.as_deref() {
row.override_route_target =
snap.session_route_target_overrides.get(session_id).cloned();
}
}
Snapshot {
rows,
recent: snap.recent,
model_overrides: snap.session_model_overrides,
overrides: snap.session_effort_overrides,
station_overrides: snap.session_station_overrides,
route_target_overrides: snap.session_route_target_overrides,
service_tier_overrides: snap.session_service_tier_overrides,
global_station_override,
global_route_target_override,
station_meta_overrides: config_meta,
usage_rollup: snap.usage_rollup,
provider_balances: snap.provider_balances,
station_health,
health_checks: snap.health_checks,
lb_view: snap.lb_view,
stats_5m: snap.stats_5m,
stats_1h: snap.stats_1h,
pricing_catalog: crate::pricing::operator_model_price_catalog_snapshot(),
refreshed_at: Instant::now(),
}
}
pub(in crate::tui) fn filtered_requests_len(
snapshot: &Snapshot,
selected_session_idx: usize,
) -> usize {
let selected_sid = snapshot
.rows
.get(selected_session_idx)
.and_then(|r| r.session_id.as_deref());
snapshot
.recent
.iter()
.filter(|r| match (selected_sid, r.session_id.as_deref()) {
(Some(sid), Some(rid)) => sid == rid,
(Some(_), None) => false,
(None, _) => true,
})
.take(60)
.count()
}
pub(in crate::tui) fn find_session_idx(snapshot: &Snapshot, sid: &str) -> Option<usize> {
snapshot
.rows
.iter()
.position(|row| row.session_id.as_deref() == Some(sid))
}
pub(in crate::tui) fn request_page_focus_session_id(
snapshot: &Snapshot,
explicit_focus: Option<&str>,
selected_session_idx: usize,
) -> Option<String> {
explicit_focus.map(ToOwned::to_owned).or_else(|| {
snapshot
.rows
.get(selected_session_idx)
.and_then(|row| row.session_id.clone())
})
}
pub(in crate::tui) fn request_matches_page_filters(
request: &FinishedRequest,
errors_only: bool,
scope_session: bool,
focused_sid: Option<&str>,
) -> bool {
if errors_only && request.status_code < 400 {
return false;
}
if !scope_session {
return true;
}
match (focused_sid, request.session_id.as_deref()) {
(Some(sid), Some(request_sid)) => sid == request_sid,
(Some(_), None) => false,
(None, _) => true,
}
}
pub(in crate::tui) fn filtered_request_page_len(
snapshot: &Snapshot,
explicit_focus: Option<&str>,
selected_session_idx: usize,
errors_only: bool,
scope_session: bool,
) -> usize {
let focused_sid = request_page_focus_session_id(snapshot, explicit_focus, selected_session_idx);
snapshot
.recent
.iter()
.filter(|request| {
request_matches_page_filters(
request,
errors_only,
scope_session,
focused_sid.as_deref(),
)
})
.count()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::FinishedRequest;
use unicode_width::UnicodeWidthStr;
fn empty_session_row() -> SessionRow {
SessionRow {
session_id: Some("sid".to_string()),
observation_scope: SessionObservationScope::ObservedOnly,
host_local_transcript_path: None,
last_client_name: None,
last_client_addr: None,
cwd: None,
active_count: 0,
active_started_at_ms_min: None,
active_last_method: None,
active_last_path: None,
last_status: None,
last_duration_ms: None,
last_ended_at_ms: None,
last_model: None,
last_reasoning_effort: None,
last_service_tier: None,
last_provider_id: None,
last_station_name: None,
last_upstream_base_url: None,
last_usage: None,
total_usage: None,
turns_total: None,
turns_with_usage: None,
binding_profile_name: None,
binding_continuity_mode: None,
last_route_decision: None,
route_affinity: None,
effective_model: None,
effective_reasoning_effort: None,
effective_service_tier: None,
effective_station: None,
effective_upstream_base_url: None,
override_model: None,
override_effort: None,
override_station_name: None,
override_route_target: None,
override_service_tier: None,
}
}
#[test]
fn basename_handles_unix_and_windows_paths() {
assert_eq!(basename("/a/b/c"), "c");
assert_eq!(basename("/a/b/c/"), "c");
assert_eq!(basename(r"C:\a\b\c"), "c");
assert_eq!(basename(r"C:\a\b\c\"), "c");
}
#[test]
fn shorten_respects_display_width_cjk() {
let s = "你好世界";
let out = shorten(s, 5);
assert_eq!(out, "你好…");
assert_eq!(UnicodeWidthStr::width(out.as_str()), 5);
}
#[test]
fn shorten_middle_keeps_both_ends() {
let s = "abcdef";
assert_eq!(shorten_middle(s, 5), "ab…ef");
}
#[test]
fn provider_balance_compact_includes_plan_and_amount() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Ok,
plan_name: Some("CodeX Air".to_string()),
total_balance_usd: Some("165.08".to_string()),
..ProviderBalanceSnapshot::default()
};
assert_eq!(
provider_balance_compact(&snapshot, 80),
"CodeX Air left $165.08"
);
}
#[test]
fn provider_balance_compact_prefers_wallet_when_quota_is_also_present() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Ok,
plan_name: Some("RightCode Daily".to_string()),
total_balance_usd: Some("3.25".to_string()),
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("7.5".to_string()),
quota_limit_usd: Some("20".to_string()),
..ProviderBalanceSnapshot::default()
};
assert_eq!(
provider_balance_compact(&snapshot, 120),
"RightCode Daily left $3.25 | daily left $7.50 / $20.00"
);
assert_eq!(provider_balance_compact(&snapshot, 18), "$3.25");
}
#[test]
fn session_route_target_counts_as_manual_override() {
let mut row = empty_session_row();
row.override_route_target = Some("monthly.default".to_string());
assert!(session_row_has_any_override(&row));
assert_eq!(session_override_fields(&row), vec!["route target"]);
}
#[test]
fn provider_balance_compact_prefers_unlimited_over_spend() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Ok,
plan_name: Some("cx".to_string()),
unlimited_quota: Some(true),
quota_used_usd: Some("106065.94".to_string()),
..ProviderBalanceSnapshot::default()
};
assert_eq!(provider_balance_compact(&snapshot, 80), "cx unlimited");
}
#[test]
fn provider_balance_compact_shows_quota_window_instead_of_spend() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Exhausted,
plan_name: Some("CodeX Lite 年度".to_string()),
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("0".to_string()),
quota_limit_usd: Some("100".to_string()),
quota_used_usd: Some("100.468025".to_string()),
..ProviderBalanceSnapshot::default()
};
assert_eq!(
provider_balance_compact(&snapshot, 120),
"exh CodeX Lite 年度 daily left $0 / $100.00"
);
assert_eq!(provider_balance_compact(&snapshot, 14), "$0/$100.00");
}
#[test]
fn provider_balance_compact_falls_back_to_status_in_too_narrow_cells() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Exhausted,
exhausted: Some(true),
exhaustion_affects_routing: false,
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("0".to_string()),
quota_limit_usd: Some("300".to_string()),
..ProviderBalanceSnapshot::default()
};
let en = provider_balance_compact(&snapshot, 4);
assert_eq!(en, "lazy");
assert!(!en.contains('$'), "{en}");
assert!(!en.contains('…'), "{en}");
let zh = provider_balance_compact_lang(&snapshot, 6, Language::Zh);
assert_eq!(zh, "不降级");
assert!(!zh.contains('$'), "{zh}");
assert!(!zh.contains('…'), "{zh}");
}
#[test]
fn provider_balance_compact_marks_ignored_exhaustion_as_lazy() {
let snapshot = ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Exhausted,
exhausted: Some(true),
exhaustion_affects_routing: false,
plan_name: Some("CodeX Lite 年度".to_string()),
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("0".to_string()),
quota_limit_usd: Some("100".to_string()),
..ProviderBalanceSnapshot::default()
};
assert_eq!(
provider_balance_compact(&snapshot, 120),
"lazy CodeX Lite 年度 daily left $0 / $100.00"
);
assert_eq!(balance_snapshot_status_label(&snapshot), "lazy reset");
}
#[test]
fn station_balance_brief_prefers_usable_snapshot_and_keeps_warnings() {
let balances = HashMap::from([(
"input".to_string(),
vec![
ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Exhausted,
..ProviderBalanceSnapshot::default()
},
ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Ok,
total_balance_usd: Some("12.50".to_string()),
..ProviderBalanceSnapshot::default()
},
],
)]);
assert_eq!(
station_balance_brief(&balances, "input", 24),
"left $12.50 exh 1"
);
assert_eq!(
station_primary_balance_snapshot(&balances, "input").map(|snapshot| snapshot.status),
Some(BalanceSnapshotStatus::Ok)
);
}
#[test]
fn station_balance_brief_marks_ignored_exhaustion_as_lazy() {
let balances = HashMap::from([(
"input".to_string(),
vec![ProviderBalanceSnapshot {
status: BalanceSnapshotStatus::Exhausted,
exhausted: Some(true),
exhaustion_affects_routing: false,
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("0".to_string()),
quota_limit_usd: Some("100".to_string()),
..ProviderBalanceSnapshot::default()
}],
)]);
assert_eq!(
station_balance_brief(&balances, "input", 80),
"lazy daily left $0 / $100.00"
);
}
#[test]
fn station_balance_brief_keeps_quota_amount_complete_when_counts_overflow() {
let mut snapshots = vec![ProviderBalanceSnapshot {
provider_id: "routing".to_string(),
status: BalanceSnapshotStatus::Ok,
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("93.83".to_string()),
quota_limit_usd: Some("100".to_string()),
..ProviderBalanceSnapshot::default()
}];
snapshots.extend((0..4).map(|_| ProviderBalanceSnapshot {
provider_id: "routing".to_string(),
status: BalanceSnapshotStatus::Exhausted,
exhausted: Some(true),
exhaustion_affects_routing: false,
..ProviderBalanceSnapshot::default()
}));
snapshots.push(ProviderBalanceSnapshot {
provider_id: "routing".to_string(),
status: BalanceSnapshotStatus::Error,
..ProviderBalanceSnapshot::default()
});
let balances = HashMap::from([("routing".to_string(), snapshots)]);
let brief = station_balance_brief_lang(&balances, "routing", 42, Language::Zh);
assert_eq!(brief, "daily 剩余 $93.83 / $100.00 不降级 4");
assert!(!brief.contains('…'), "{brief}");
assert!(brief.contains("$100.00"), "{brief}");
assert!(UnicodeWidthStr::width(brief.as_str()) <= 42, "{brief}");
let narrow = station_balance_brief_lang(&balances, "routing", 14, Language::Zh);
assert_eq!(narrow, "$93.83/$100.00");
assert!(UnicodeWidthStr::width(narrow.as_str()) <= 14, "{narrow}");
}
#[test]
fn session_balance_brief_uses_observed_station_then_provider_fallback() {
let balances = HashMap::from([(
"input".to_string(),
vec![ProviderBalanceSnapshot {
provider_id: "input-provider".to_string(),
status: BalanceSnapshotStatus::Ok,
plan_name: Some("Monthly".to_string()),
total_balance_usd: Some("8.00".to_string()),
..ProviderBalanceSnapshot::default()
}],
)]);
let mut row = empty_session_row();
row.last_station_name = Some("input".to_string());
assert_eq!(
session_balance_brief(&row, &balances, 80).as_deref(),
Some("Monthly left $8.00")
);
row.last_station_name = None;
row.last_provider_id = Some("input-provider".to_string());
assert_eq!(
session_balance_brief(&row, &balances, 80).as_deref(),
Some("input Monthly left $8.00")
);
}
#[test]
fn session_observed_provider_balance_follows_provider_not_station_summary() {
let balances = HashMap::from([(
"input".to_string(),
vec![
ProviderBalanceSnapshot {
provider_id: "input".to_string(),
status: BalanceSnapshotStatus::Ok,
unlimited_quota: Some(true),
..ProviderBalanceSnapshot::default()
},
ProviderBalanceSnapshot {
provider_id: "centos".to_string(),
status: BalanceSnapshotStatus::Exhausted,
exhausted: Some(true),
exhaustion_affects_routing: false,
quota_period: Some("daily".to_string()),
quota_remaining_usd: Some("0".to_string()),
quota_limit_usd: Some("100".to_string()),
..ProviderBalanceSnapshot::default()
},
],
)]);
let mut row = empty_session_row();
row.last_station_name = Some("input".to_string());
row.last_provider_id = Some("centos".to_string());
let brief = session_observed_provider_balance_brief_lang(&row, &balances, 80, Language::En);
assert_eq!(brief.as_deref(), Some("lazy daily left $0 / $100.00"));
assert_eq!(
session_observed_provider_balance_snapshot(&row, &balances)
.map(|snapshot| snapshot.provider_id.as_str()),
Some("centos")
);
}
#[test]
fn duration_short_uses_readable_units() {
assert_eq!(duration_short(842), "842ms");
assert_eq!(duration_short(1_250), "1.2s");
assert_eq!(duration_short(12_000), "12s");
assert_eq!(duration_short(83_000), "1m23s");
}
#[test]
fn provider_tags_brief_filters_internal_tags() {
let provider = ProviderOption {
name: "input".to_string(),
upstreams: vec![UpstreamSummary {
provider_id: Some("input".to_string()),
tags: vec![
("provider_id".to_string(), "input".to_string()),
("source".to_string(), "codex-config".to_string()),
("billing".to_string(), "monthly".to_string()),
("region".to_string(), "hk".to_string()),
],
..UpstreamSummary::default()
}],
..ProviderOption::default()
};
assert_eq!(
provider_tags_brief(&provider, 80).as_deref(),
Some("billing=monthly region=hk")
);
}
#[test]
fn request_page_focus_session_prefers_explicit_focus() {
let snapshot = Snapshot {
rows: vec![SessionRow {
session_id: Some("sid-selected".to_string()),
observation_scope: SessionObservationScope::ObservedOnly,
host_local_transcript_path: None,
last_client_name: None,
last_client_addr: None,
cwd: None,
active_count: 0,
active_started_at_ms_min: None,
active_last_method: None,
active_last_path: None,
last_status: None,
last_duration_ms: None,
last_ended_at_ms: None,
last_model: None,
last_reasoning_effort: None,
last_service_tier: None,
last_provider_id: None,
last_station_name: None,
last_upstream_base_url: None,
last_usage: None,
total_usage: None,
turns_total: None,
turns_with_usage: None,
binding_profile_name: None,
binding_continuity_mode: None,
last_route_decision: None,
route_affinity: None,
effective_model: None,
effective_reasoning_effort: None,
effective_service_tier: None,
effective_station: None,
effective_upstream_base_url: None,
override_model: None,
override_effort: None,
override_station_name: None,
override_route_target: None,
override_service_tier: None,
}],
recent: Vec::new(),
model_overrides: HashMap::new(),
overrides: HashMap::new(),
station_overrides: HashMap::new(),
route_target_overrides: HashMap::new(),
service_tier_overrides: HashMap::new(),
global_station_override: None,
global_route_target_override: None,
station_meta_overrides: HashMap::new(),
usage_rollup: UsageRollupView::default(),
provider_balances: HashMap::new(),
station_health: HashMap::new(),
health_checks: HashMap::new(),
lb_view: HashMap::new(),
stats_5m: WindowStats::default(),
stats_1h: WindowStats::default(),
pricing_catalog: crate::pricing::bundled_model_price_catalog_snapshot(),
refreshed_at: Instant::now(),
};
let focused = request_page_focus_session_id(&snapshot, Some("sid-explicit"), 0);
assert_eq!(focused.as_deref(), Some("sid-explicit"));
}
#[test]
fn filtered_request_page_len_uses_explicit_focus() {
let snapshot = Snapshot {
rows: vec![SessionRow {
session_id: Some("sid-selected".to_string()),
observation_scope: SessionObservationScope::ObservedOnly,
host_local_transcript_path: None,
last_client_name: None,
last_client_addr: None,
cwd: None,
active_count: 0,
active_started_at_ms_min: None,
active_last_method: None,
active_last_path: None,
last_status: None,
last_duration_ms: None,
last_ended_at_ms: None,
last_model: None,
last_reasoning_effort: None,
last_service_tier: None,
last_provider_id: None,
last_station_name: None,
last_upstream_base_url: None,
last_usage: None,
total_usage: None,
turns_total: None,
turns_with_usage: None,
binding_profile_name: None,
binding_continuity_mode: None,
last_route_decision: None,
route_affinity: None,
effective_model: None,
effective_reasoning_effort: None,
effective_service_tier: None,
effective_station: None,
effective_upstream_base_url: None,
override_model: None,
override_effort: None,
override_station_name: None,
override_route_target: None,
override_service_tier: None,
}],
recent: vec![
FinishedRequest {
id: 1,
trace_id: Some("codex-1".to_string()),
session_id: Some("sid-selected".to_string()),
client_name: None,
client_addr: None,
cwd: None,
model: None,
reasoning_effort: None,
service_tier: None,
station_name: None,
provider_id: None,
upstream_base_url: None,
route_decision: None,
usage: None,
cost: crate::pricing::CostBreakdown::default(),
retry: None,
observability: crate::state::RequestObservability::default(),
service: "codex".to_string(),
method: "POST".to_string(),
path: "/v1/responses".to_string(),
status_code: 200,
duration_ms: 120,
ttfb_ms: None,
streaming: false,
ended_at_ms: 1,
},
FinishedRequest {
id: 2,
trace_id: Some("codex-2".to_string()),
session_id: Some("sid-explicit".to_string()),
client_name: None,
client_addr: None,
cwd: None,
model: None,
reasoning_effort: None,
service_tier: None,
station_name: None,
provider_id: None,
upstream_base_url: None,
route_decision: None,
usage: None,
cost: crate::pricing::CostBreakdown::default(),
retry: None,
observability: crate::state::RequestObservability::default(),
service: "codex".to_string(),
method: "POST".to_string(),
path: "/v1/responses".to_string(),
status_code: 200,
duration_ms: 120,
ttfb_ms: None,
streaming: false,
ended_at_ms: 2,
},
],
model_overrides: HashMap::new(),
overrides: HashMap::new(),
station_overrides: HashMap::new(),
route_target_overrides: HashMap::new(),
service_tier_overrides: HashMap::new(),
global_station_override: None,
global_route_target_override: None,
station_meta_overrides: HashMap::new(),
usage_rollup: UsageRollupView::default(),
provider_balances: HashMap::new(),
station_health: HashMap::new(),
health_checks: HashMap::new(),
lb_view: HashMap::new(),
stats_5m: WindowStats::default(),
stats_1h: WindowStats::default(),
pricing_catalog: crate::pricing::bundled_model_price_catalog_snapshot(),
refreshed_at: Instant::now(),
};
let count = filtered_request_page_len(&snapshot, Some("sid-explicit"), 0, false, true);
assert_eq!(count, 1);
}
#[test]
fn build_session_rows_from_cards_skips_sessionless_cards() {
let rows = build_session_rows_from_cards(&[
SessionIdentityCard {
session_id: None,
..SessionIdentityCard::default()
},
SessionIdentityCard {
session_id: Some("sid-1".to_string()),
..SessionIdentityCard::default()
},
]);
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].session_id.as_deref(), Some("sid-1"));
}
#[test]
fn build_session_rows_from_cards_preserves_route_affinity() {
let rows = build_session_rows_from_cards(&[SessionIdentityCard {
session_id: Some("sid-1".to_string()),
route_affinity: Some(SessionRouteAffinity {
route_graph_key: "v4:deadbeef".to_string(),
provider_endpoint: codex_helper_core::runtime_identity::ProviderEndpointKey::new(
"codex", "right", "default",
),
upstream_base_url: "https://right.example/v1".to_string(),
route_path: vec!["monthly_first".to_string(), "right".to_string()],
last_selected_at_ms: 1_000,
last_changed_at_ms: 900,
change_reason: "failover_after_status_502".to_string(),
}),
..SessionIdentityCard::default()
}]);
assert_eq!(rows.len(), 1);
assert_eq!(
rows[0]
.route_affinity
.as_ref()
.map(|affinity| affinity.provider_endpoint.provider_id.as_str()),
Some("right")
);
assert_eq!(
rows[0]
.route_affinity
.as_ref()
.map(|affinity| affinity.change_reason.as_str()),
Some("failover_after_status_502")
);
}
#[test]
fn session_control_posture_reports_profile_overrides() {
let row = SessionRow {
session_id: Some("sid-1".to_string()),
observation_scope: SessionObservationScope::ObservedOnly,
host_local_transcript_path: None,
last_client_name: None,
last_client_addr: None,
cwd: None,
active_count: 0,
active_started_at_ms_min: None,
active_last_method: None,
active_last_path: None,
last_status: None,
last_duration_ms: None,
last_ended_at_ms: None,
last_model: None,
last_reasoning_effort: None,
last_service_tier: None,
last_provider_id: None,
last_station_name: None,
last_upstream_base_url: None,
last_usage: None,
total_usage: None,
turns_total: None,
turns_with_usage: None,
binding_profile_name: Some("fast".to_string()),
binding_continuity_mode: None,
last_route_decision: None,
route_affinity: None,
effective_model: None,
effective_reasoning_effort: None,
effective_service_tier: None,
effective_station: None,
effective_upstream_base_url: None,
override_model: Some("gpt-5.4".to_string()),
override_effort: None,
override_station_name: None,
override_route_target: None,
override_service_tier: None,
};
let posture = session_control_posture(&row, None, None, false);
assert!(posture.headline.contains("profile fast"));
assert!(posture.detail.contains("model"));
}
#[test]
fn session_control_posture_reports_route_graph_override_context() {
let mut row = empty_session_row();
row.override_route_target = Some("monthly.default".to_string());
let posture = session_control_posture(&row, None, Some("input.fast"), true);
assert!(posture.headline.contains("session-controlled route"));
assert!(posture.detail.contains("route target"));
}
#[test]
fn session_control_posture_reports_global_route_target_context() {
let row = empty_session_row();
let posture = session_control_posture(&row, None, Some("input.fast"), true);
assert!(posture.headline.contains("global route target input.fast"));
assert!(posture.detail.contains("route graph defaults"));
}
}