Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/provider_detail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ pub struct ProviderDetail {
/// Locale key naming the tertiary lane when it carries a semantic label
/// beyond "Tertiary" (upstream F5). Drives the settings metric picker.
pub tertiary_label_key: Option<&'static str>,
/// Id of the extra rate window holding the provider's monthly plan
/// allowance (upstream 0.70.0 #4072). Offers the Monthly Plan metric in
/// the settings metric picker.
pub monthly_plan_window_id: Option<&'static str>,
/// Metric picker label for the primary lane when it is not a session
/// window (upstream `menuBarLayoutPrimaryLabel`).
pub primary_metric_label: Option<&'static str>,
pub extra_rate_windows: Vec<NamedRateWindowSnapshot>,
pub usage_items: Vec<ProviderUsageItemSnapshot>,
pub hidden_usage_item_ids: Vec<String>,
Expand Down Expand Up @@ -100,6 +107,8 @@ pub(crate) fn build_provider_detail(
model_specific: None,
tertiary: None,
tertiary_label_key: metadata.tertiary_label_key,
monthly_plan_window_id: provider.monthly_plan_window_id(),
primary_metric_label: provider.menu_bar_primary_label(),
extra_rate_windows: Vec::new(),
usage_items: Vec::new(),
hidden_usage_item_ids: settings.hidden_usage_item_ids(id),
Expand Down
73 changes: 55 additions & 18 deletions apps/desktop-tauri/src-tauri/src/tray_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ fn status_labels_for_settings(
if settings.tray_icon_mode == TrayIconMode::PerProvider {
return healthy
.into_iter()
.map(|s| provider_status_label(s, lang))
.map(|s| provider_status_label(s, settings, lang))
.collect::<Vec<_>>();
}

Expand All @@ -524,7 +524,7 @@ fn status_labels_for_settings(
return vec![];
};

let (_, label) = provider_status_label(selected, lang);
let (_, label) = provider_status_label(selected, settings, lang);
vec![("status_summary".to_string(), label)]
}

Expand Down Expand Up @@ -554,25 +554,34 @@ fn ordered_snapshot_refs<'a>(

fn provider_status_label(
snapshot: &crate::commands::ProviderUsageSnapshot,
settings: &Settings,
lang: codexbar::settings::Language,
) -> (String, String) {
// MonthlyPlan metric (PAYG spend, e.g. Mistral): show formatted cost.
let provider = codexbar::core::ProviderId::from_cli_name(&snapshot.provider_id);
let preference = provider
.map(|id| Settings::load().get_provider_metric(id))
.map(|id| settings.get_provider_metric(id))
.unwrap_or_default();
if preference == MetricPreference::MonthlyPlan
&& let Some(cost) = snapshot.cost.as_ref()
{
let amount = if !cost.formatted_used.is_empty() {
cost.formatted_used.clone()
} else {
crate::commands::format_cost_amount(cost)
};
return (
snapshot.provider_id.clone(),
format!("{} {}", snapshot.display_name, amount),
);
if preference == MetricPreference::MonthlyPlan {
// Upstream 0.70.0 (#4072): label the provider's plan allowance when
// it resolves, otherwise keep the current-month spend amount.
if let Some(plan) = crate::usage_metric::monthly_plan_window(snapshot, provider) {
let label = crate::commands::compact_tray_status_label(plan, lang);
return (
snapshot.provider_id.clone(),
format!("{} {}", snapshot.display_name, label),
);
}
if let Some(cost) = snapshot.cost.as_ref() {
let amount = if !cost.formatted_used.is_empty() {
cost.formatted_used.clone()
} else {
crate::commands::format_cost_amount(cost)
};
return (
snapshot.provider_id.clone(),
format!("{} {}", snapshot.display_name, amount),
);
}
}

let label = crate::commands::compact_tray_status_label(headline_window(snapshot), lang);
Expand Down Expand Up @@ -1315,14 +1324,42 @@ mod tests {
"{japanese_tooltip}"
);

let settings = Settings::default();
let (_, english_label) =
provider_status_label(&claude, codexbar::settings::Language::English);
provider_status_label(&claude, &settings, codexbar::settings::Language::English);
let (_, japanese_label) =
provider_status_label(&claude, codexbar::settings::Language::Japanese);
provider_status_label(&claude, &settings, codexbar::settings::Language::Japanese);
assert!(english_label.contains("Resets in"), "{english_label}");
assert!(japanese_label.contains("リセットまで"), "{japanese_label}");
}

#[test]
fn mistral_monthly_plan_tray_label_shows_the_plan_then_the_spend() {
let mut settings = Settings::default();
settings.set_provider_metric(ProviderId::Mistral, MetricPreference::MonthlyPlan);
settings.show_as_used = true;
let lang = codexbar::settings::Language::English;
let mut mistral =
fake_snapshot_with("mistral", "Mistral", 2.0, None, None, Some((12.5, 50.0)));
let mut plan = fake_extra_window(42.0);
plan.id = codexbar::providers::mistral::MONTHLY_PLAN_WINDOW_ID.to_string();
plan.title = "Monthly Plan".to_string();
mistral.extra_rate_windows = vec![plan];

let (_, label) = provider_status_label(&mistral, &settings, lang);
assert_eq!(label, "Mistral 42%");
assert_eq!(selected_tray_percents(&mistral, &settings).0, 42.0);

// Without a known plan allowance the label keeps the spend text.
mistral.extra_rate_windows[0].window.is_informational = true;
let (_, label) = provider_status_label(&mistral, &settings, lang);
assert_eq!(label, "Mistral $12.50");

// Automatic keeps the existing headline label.
let (_, label) = provider_status_label(&mistral, &Settings::default(), lang);
assert_eq!(label, "Mistral 2%");
}

#[test]
fn selected_tray_percent_uses_cursor_extra_usage_cost() {
let mut settings = Settings::default();
Expand Down
149 changes: 148 additions & 1 deletion apps/desktop-tauri/src-tauri/src/usage_metric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,44 @@ fn preferred_window(
extra_usage_window(snapshot).or_else(|| cost_window(snapshot))
}
MetricPreference::Average => average_window(snapshot),
MetricPreference::MonthlyPlan => cost_window(snapshot),
// Upstream 0.70.0 (#4072): the provider's plan allowance. A missing
// or unknown plan falls back to the primary (included API) allowance,
// never to a spend window. Providers without a plan window fall
// through to Automatic.
MetricPreference::MonthlyPlan => {
let window_id = provider.and_then(monthly_plan_window_id)?;
plan_window(snapshot, window_id)
.or_else(|| non_informational(Some(&snapshot.primary)))
.cloned()
}
}
}

/// The provider-declared monthly plan allowance, when the snapshot carries a
/// known value for it. Providers without a plan window return `None`.
pub(crate) fn monthly_plan_window(
snapshot: &ProviderUsageSnapshot,
provider: Option<ProviderId>,
) -> Option<&RateWindowSnapshot> {
plan_window(snapshot, provider.and_then(monthly_plan_window_id)?)
}

fn monthly_plan_window_id(provider: ProviderId) -> Option<&'static str> {
codexbar::core::instantiate_provider(provider).monthly_plan_window_id()
}

fn plan_window<'a>(
snapshot: &'a ProviderUsageSnapshot,
window_id: &str,
) -> Option<&'a RateWindowSnapshot> {
snapshot
.extra_rate_windows
.iter()
.find(|extra| extra.id == window_id)
.map(|extra| &extra.window)
.filter(|window| !window.is_informational)
}

fn automatic_window(
snapshot: &ProviderUsageSnapshot,
provider: Option<ProviderId>,
Expand Down Expand Up @@ -606,6 +640,119 @@ mod tests {
assert_eq!(selected.remaining_percent, 60.0);
}

fn mistral_snapshot(plan: Option<RateWindowSnapshot>) -> ProviderUsageSnapshot {
let mut snapshot = snapshot();
snapshot.provider_id = "mistral".to_string();
snapshot.display_name = "Mistral".to_string();
snapshot.primary = window(2.0);
snapshot.primary_label = Some("Included API".to_string());
snapshot.secondary = None;
snapshot.extra_rate_windows = plan
.map(|window| crate::commands::NamedRateWindowSnapshot {
id: codexbar::providers::mistral::MONTHLY_PLAN_WINDOW_ID.to_string(),
title: "Monthly Plan".to_string(),
window,
fallback_lane: false,
})
.into_iter()
.collect();
snapshot
}

fn metric_settings(provider: ProviderId, preference: MetricPreference) -> Settings {
let mut settings = Settings::default();
settings.set_provider_metric(provider, preference);
settings
}

#[test]
fn mistral_monthly_plan_selects_the_vibe_plan_window() {
let mut snapshot = mistral_snapshot(Some(window(42.0)));
snapshot.primary = window(80.0);

let monthly_plan = metric_settings(ProviderId::Mistral, MetricPreference::MonthlyPlan);
assert_eq!(
selected_usage_window(&snapshot, &monthly_plan).used_percent,
42.0
);
// Included API and Automatic stay separate choices (upstream #4072).
let included_api = metric_settings(ProviderId::Mistral, MetricPreference::Session);
assert_eq!(
selected_usage_window(&snapshot, &included_api).used_percent,
80.0
);
assert_eq!(
selected_usage_window(&snapshot, &Settings::default()).used_percent,
80.0
);
let presentation =
crate::commands::ProviderUsagePresentationSnapshot::new(snapshot, &monthly_plan);
assert_eq!(presentation.selected_metric.used_percent, 42.0);
}

#[test]
fn mistral_monthly_plan_falls_back_to_included_api_without_a_known_plan() {
let settings = metric_settings(ProviderId::Mistral, MetricPreference::MonthlyPlan);
let unknown_plan = RateWindowSnapshot {
is_informational: true,
..window(0.0)
};

for snapshot in [mistral_snapshot(None), mistral_snapshot(Some(unknown_plan))] {
let selected = selected_usage_window(&snapshot, &settings);
assert_eq!(selected.used_percent, 2.0);
assert!(!selected.is_informational);
}
}

#[test]
fn mistral_monthly_plan_never_selects_a_spend_window() {
let mut snapshot = mistral_snapshot(None);
snapshot.cost = Some(crate::commands::CostSnapshotBridge {
used: 45.0,
limit: Some(50.0),
remaining: Some(5.0),
currency_code: "EUR".to_string(),
currency_symbol: Some("€".to_string()),
period: "month".to_string(),
resets_at: None,
formatted_used: "€45.00".to_string(),
formatted_limit: Some("€50.00".to_string()),
balance: None,
balance_updated_at: None,
account_id: None,
formatted_balance: None,
daily: Vec::new(),
always_visible: false,
});
let settings = metric_settings(ProviderId::Mistral, MetricPreference::MonthlyPlan);

assert_eq!(
selected_usage_window(&snapshot, &settings).used_percent,
2.0
);
}

#[test]
fn monthly_plan_without_a_provider_plan_window_falls_through_to_automatic() {
let mut snapshot = snapshot();
snapshot.extra_rate_windows = vec![crate::commands::NamedRateWindowSnapshot {
id: codexbar::providers::mistral::MONTHLY_PLAN_WINDOW_ID.to_string(),
title: "Monthly Plan".to_string(),
window: window(90.0),
fallback_lane: false,
}];
let settings = metric_settings(ProviderId::Codex, MetricPreference::MonthlyPlan);

// Codex declares no plan window, so a same-named lane is not special
// and the choice resolves like Automatic (highest real window).
assert_eq!(
selected_usage_window(&snapshot, &settings).used_percent,
selected_usage_window(&snapshot, &Settings::default()).used_percent
);
assert!(monthly_plan_window(&snapshot, Some(ProviderId::Codex)).is_none());
}

#[test]
fn presentation_payload_flattens_the_snapshot_and_selected_metric() {
let presentation = crate::commands::ProviderUsagePresentationSnapshot::new(
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop-tauri/src/i18n/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@ export const ALL_LOCALE_KEYS = [
// Mistral PAYG monthly spend (#2821, #2947)
"MistralMonthlySpend",
"MistralMonthlySpendHelper",
// Mistral Monthly Plan menu bar metric (upstream 0.70.0 #4072)
"MetricMonthlyPlan",

// Menu cost-summary display style (#2976)
"CostSummaryDisplayStyle",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@ function provider(extra = true): ProviderDetail {
};
}

function mistral(observed = true): ProviderDetail {
return {
...provider(false),
id: "mistral",
displayName: "Mistral",
primaryMetricLabel: "Included API",
monthlyPlanWindowId: "mistral-monthly-plan",
session: observed ? rateWindow(2) : null,
extraRateWindows: observed
? [{ id: "mistral-monthly-plan", title: "Monthly Plan", window: rateWindow(42) }]
: [],
hasSnapshot: observed,
};
}

function optionNames() {
return screen.getAllByRole("option").map((option) => option.textContent);
}

function rateWindow(usedPercent: number) {
return {
usedPercent,
Expand Down Expand Up @@ -122,5 +141,62 @@ describe("MenuBarMetricSection", () => {
expect(onChange).toHaveBeenCalledWith({
providerMetrics: { copilot: "extraUsage" },
});
expect(screen.queryByRole("option", { name: "MetricMonthlyPlan" })).toBeNull();
});

it("offers Included API and Monthly Plan for a provider plan window", () => {
const onChange = vi.fn();
render(
<MenuBarMetricSection
provider={mistral()}
providerMetrics={{}}
disabled={false}
t={(key) => key}
onChange={onChange}
/>,
);

// Upstream 0.70.0: Automatic, Included API and Monthly Plan only. The
// plan window does not add a separate Extra usage choice.
expect(optionNames()).toEqual(["Automatic", "Included API", "MetricMonthlyPlan"]);
fireEvent.change(screen.getByRole("combobox"), { target: { value: "monthlyPlan" } });
expect(onChange).toHaveBeenCalledWith({
providerMetrics: { mistral: "monthlyPlan" },
});
});

it("offers Monthly Plan before the first Mistral snapshot", () => {
render(
<MenuBarMetricSection
provider={mistral(false)}
providerMetrics={{ mistral: "monthlyPlan" }}
disabled={false}
t={(key) => key}
onChange={vi.fn()}
/>,
);

expect(optionNames()).toEqual(["Automatic", "Included API", "MetricMonthlyPlan"]);
expect(screen.getByRole("combobox")).toHaveValue("monthlyPlan");
});

it("keeps a saved choice the provider no longer offers readable", () => {
render(
<MenuBarMetricSection
provider={mistral()}
providerMetrics={{ mistral: "extraUsage" }}
disabled={false}
t={(key) => key}
onChange={vi.fn()}
/>,
);

expect(optionNames()).toEqual([
"Automatic",
"Included API",
"MetricMonthlyPlan",
"ExtraUsage",
]);
expect(screen.getByRole("combobox")).toHaveValue("extraUsage");
});
});
Loading