Skip to content
Merged
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
73 changes: 64 additions & 9 deletions CLI Pulse Bar/CLI Pulse Bar/OverviewTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,13 @@ struct OverviewTab: View {
// it gets the sentence-case words, not the badge's capsule text.
MetricCard(
title: L10n.dashboard.costToday,
value: CostFormatter.format(dash.total_estimated_cost_today),
// v1.56: "≈" when this is the local scan's today total (see
// `completeRefresh`) and part of it was priced at a borrowed
// rate, so it matches the cost card's Today figure below.
value: CostFormatter.format(
dash.total_estimated_cost_today,
approximate: providerState.costSummary.todayFigureIsApproximate(dash.total_estimated_cost_today)
),
subtitle: L10n.cost.statusLabel(dash.cost_status),
icon: "dollarsign.circle",
color: .green
Expand Down Expand Up @@ -369,7 +375,8 @@ struct OverviewTab: View {
// number came from; the old badge used it to make a claim about
// how accurate the number is. A local scan that priced 20% of
// its tokens is still a local scan, and this said "Exact"
// directly above the line admitting it was 20%.
// directly above the line admitting it was 20%. 1.56 adds a
// fourth, "Approximate", for a rate borrowed from another model.
let fidelity = providerState.costSummary.fidelity
let fidelityColor: Color = fidelity == .exact ? .green : .orange
Text(L10n.cost.fidelityLabel(fidelity))
Expand All @@ -387,7 +394,12 @@ struct OverviewTab: View {
.font(.system(size: 9))
.foregroundStyle(.tertiary)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(CostFormatter.format(providerState.costSummary.todayTotal))
// v1.56: "≈" when part of today's figure was charged at
// a rate borrowed from a neighbouring model.
Text(CostFormatter.format(
providerState.costSummary.todayTotal,
approximate: providerState.costSummary.todayCoverage.hasApproximatePrices
))
.font(.system(size: 16, weight: .bold, design: .rounded))
.foregroundStyle(.green)
if providerState.costSummary.todayTokens > 0 {
Expand All @@ -408,7 +420,10 @@ struct OverviewTab: View {
.font(.system(size: 9))
.foregroundStyle(.tertiary)
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(CostFormatter.format(providerState.costSummary.thirtyDayTotal))
Text(CostFormatter.format(
providerState.costSummary.thirtyDayTotal,
approximate: providerState.costSummary.coverage.hasApproximatePrices
))
.font(.system(size: 16, weight: .bold, design: .rounded))
.foregroundStyle(.green)
if providerState.costSummary.thirtyDayTokens > 0 {
Expand Down Expand Up @@ -445,7 +460,12 @@ struct OverviewTab: View {
.clipShape(Capsule())
}
Spacer()
Text(CostFormatter.format(item.cost))
// Only the 30-day breakdown (a local scan) can know;
// `approximateProviders` is empty for a server figure.
Text(CostFormatter.format(
item.cost,
approximate: providerState.costSummary.providerFigureIsApproximate(item.provider)
))
.font(.system(size: 10, weight: .medium).monospacedDigit())
.foregroundStyle(.green)
}
Expand Down Expand Up @@ -502,7 +522,13 @@ struct OverviewTab: View {
.font(.system(size: 10))
.foregroundStyle(.secondary)
Spacer()
Text(CostFormatter.format(item.apiEquivCost) + " / " + CostFormatter.format(item.subscriptionCost))
// v1.56: the API-equivalent half is the same
// 30-day scan sum as the provider's row above,
// so it carries the same "≈".
Text(CostFormatter.format(
item.apiEquivCost,
approximate: providerState.costSummary.providerFigureIsApproximate(item.provider)
) + " / " + CostFormatter.format(item.subscriptionCost))
.font(.system(size: 10, weight: .medium).monospacedDigit())
.foregroundStyle(.secondary)
}
Expand Down Expand Up @@ -548,7 +574,10 @@ struct OverviewTab: View {
.font(.system(size: 9))
.foregroundStyle(.secondary)
Spacer()
Text(CostFormatter.format(providerState.costSummary.thirtyDayTotal))
Text(CostFormatter.format(
providerState.costSummary.thirtyDayTotal,
approximate: providerState.costSummary.coverage.hasApproximatePrices
))
.font(.system(size: 10, weight: .medium).monospacedDigit())
.foregroundStyle(.green)
}
Expand Down Expand Up @@ -580,7 +609,25 @@ struct OverviewTab: View {
Spacer()
}
.help(L10n.cost.coverageHelp(
coverage.unpricedModels.prefix(6).joined(separator: ", ")
CostCoverage.tooltipList(coverage.unpricedModels)
))
}

// v1.56 — the same honesty for a borrowed rate. A model
// with no price entry is priced at a related model's rate;
// that keeps it out of "$0", and until now nothing said
// the rate was not its own. The figures above carry "≈";
// this line says why, and the help names the models.
if providerState.costSummary.coverage.hasApproximatePrices {
let coverage = providerState.costSummary.coverage
HStack(spacing: 4) {
Text(L10n.cost.approximateSummary(coverage.approximateModels.count))
.font(.system(size: 9))
.foregroundStyle(.orange)
Spacer()
}
.help(L10n.cost.approximateHelp(
CostCoverage.tooltipList(coverage.approximateModels)
))
}

Expand Down Expand Up @@ -622,9 +669,17 @@ struct OverviewTab: View {
Text(L10n.cost.tokensValue(TokenFormatter.format(item.totalTokens)))
.font(.system(size: 8))
.foregroundStyle(.tertiary)
Text(CostFormatter.format(item.cost))
Text(CostFormatter.format(
item.cost,
approximate: providerState.costSummary.coverage.approximateModels.contains(item.model)
))
.font(.system(size: 9, weight: .medium).monospacedDigit())
.foregroundStyle(.green)
// "≈" makes a 5-digit figure 11 characters,
// which can be more than 55 pt holds at
// 9 pt; shrink it rather than wrap or cut it.
.lineLimit(1)
.minimumScaleFactor(0.75)
.frame(width: 55, alignment: .trailing)
}
GeometryReader { geo in
Expand Down
22 changes: 16 additions & 6 deletions CLI Pulse Bar/CLI Pulse Bar/ProvidersTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ struct ProvidersTab: View {
Text(L10n.dashboard.today)
.font(.system(size: 8))
.foregroundStyle(.tertiary)
Text(CostFormatter.format(providerState.costSummary.todayTotal))
Text(CostFormatter.format(
providerState.costSummary.todayTotal,
approximate: providerState.costSummary.todayCoverage.hasApproximatePrices
))
.font(.system(size: 13, weight: .bold, design: .rounded))
.foregroundStyle(.green)
}
Expand All @@ -183,7 +186,10 @@ struct ProvidersTab: View {
Text(L10n.dashboard.thirtyDayEst)
.font(.system(size: 8))
.foregroundStyle(.tertiary)
Text(CostFormatter.format(providerState.costSummary.thirtyDayTotal))
Text(CostFormatter.format(
providerState.costSummary.thirtyDayTotal,
approximate: providerState.costSummary.coverage.hasApproximatePrices
))
.font(.system(size: 13, weight: .bold, design: .rounded))
.foregroundStyle(.green)
}
Expand Down Expand Up @@ -496,7 +502,7 @@ struct EnhancedProviderCard: View {
private var isQuotaProvider: Bool { provider.metadata?.supports_quota ?? false }

@ViewBuilder
private func usageColumn(header: String, metric: CardMetric, cost: Double) -> some View {
private func usageColumn(header: String, metric: CardMetric, cost: Double, approximateCost: Bool) -> some View {
VStack(alignment: .leading, spacing: 2) {
Text(header)
.font(.system(size: 9))
Expand All @@ -511,7 +517,9 @@ struct EnhancedProviderCard: View {
.help(metric.breakdownTooltip)
}
if showCost {
Text(CostFormatter.format(cost))
// v1.56: "≈" when part of the cost was charged at a rate
// borrowed from a neighbouring model.
Text(CostFormatter.format(cost, approximate: approximateCost))
.font(.system(size: 10, weight: .medium))
.foregroundStyle(.green)
}
Expand Down Expand Up @@ -776,8 +784,10 @@ struct EnhancedProviderCard: View {
let today = metric(for: Date())
let week = metric(for: nil, weekRolling: true)
HStack(spacing: 12) {
usageColumn(header: L10n.dashboard.today, metric: today, cost: provider.estimated_cost_today)
usageColumn(header: L10n.providers.thisWeek, metric: week, cost: provider.estimated_cost_week)
usageColumn(header: L10n.dashboard.today, metric: today, cost: provider.estimated_cost_today,
approximateCost: state.scanPriceIsApproximate(for: provider.provider, onDate: Date()))
usageColumn(header: L10n.providers.thisWeek, metric: week, cost: provider.estimated_cost_week,
approximateCost: state.scanPriceIsApproximateThisWeek(for: provider.provider))
Spacer()
}

Expand Down
26 changes: 26 additions & 0 deletions CLI Pulse Bar/CLIPulseCore/Sources/CLIPulseCore/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,32 @@ public final class AppState: ObservableObject {
return total > 0 ? total : nil
}

/// v1.56: whether any of `provider`'s scanned cost on `onDate` (every
/// scanned day when nil) was charged at a rate borrowed from a neighbouring
/// model. The provider card shows that cost as "≈$…".
///
/// The card's figure can be the cloud's rather than this scan's (it shows
/// the larger). The cloud's includes what this Mac uploaded, priced with
/// this table, and can also include other Macs' uploads, priced with
/// whatever table their version carries. The mark says this Mac's part
/// includes a borrowed rate; it cannot vouch for the other Macs' part.
public func scanPriceIsApproximate(for provider: String, onDate: Date? = nil) -> Bool {
guard let scan = costUsageScanResult else { return false }
let key = onDate.map { DayKey.string(from: $0) } // the scanner's Gregorian keys
return scan.entries.contains {
$0.provider == provider && $0.priceIsApproximate && (key == nil || $0.date == key)
}
}

/// `scanPriceIsApproximate` over the rolling 7-day window.
public func scanPriceIsApproximateThisWeek(for provider: String) -> Bool {
guard let scan = costUsageScanResult else { return false }
let cutoffKey = DateRange.rollingWeekStartYMD(from: Date())
return scan.entries.contains {
$0.provider == provider && $0.priceIsApproximate && $0.date >= cutoffKey
}
}

public func scanMessagesThisWeek(for provider: String) -> Int? {
guard let scan = costUsageScanResult, !scan.entries.isEmpty else { return nil }
let cutoffKey = DateRange.rollingWeekStartYMD(from: Date())
Expand Down
Loading
Loading