Skip to content

Add multi-currency cost display support #247

@chernistry

Description

@chernistry

What

Costs are currently hardcoded to USD ($X.XX). Add a configurable currency setting so users can see costs in EUR, GBP, JPY, etc. with a configurable exchange rate.

Why

Bernstein is used internationally. Seeing costs in your local currency makes budgeting more intuitive.

Where the current formatting lives

All cost formatting is in src/bernstein/cli/cost.py. Search for $ to find every place:

# Line 66-70 — main cost display
cons.print(f"  Single agent  [red]{single_bar}[/red]  [dim]${single_agent_cost:.4f}[/dim]")
cons.print(f"  Bernstein     [green]{bernstein_bar}[/green]  [bold green]${actual_cost:.4f}[/bold green]")

# Line 98-101 — summary
lines.append(f"   Cost:  ${actual_cost:.2f}")

# Line 418-419 — model breakdown
cost_str = f"${v['cost_usd']:.4f}"

# Line 439 — total
f"[bold green]${totals['cost_usd']:.4f}[/bold green]"

How to implement

Step 1: Add a format_cost() helper

Create a small helper in src/bernstein/core/cost.py (where MODEL_COSTS_PER_1M_TOKENS already lives):

# Currency symbols for display
CURRENCY_SYMBOLS: dict[str, str] = {
    "USD": "$",
    "EUR": "€",
    "GBP": "£",
    "JPY": "¥",
    "CAD": "CA$",
    "AUD": "A$",
    "CHF": "CHF ",
    "CNY": "¥",
    "KRW": "₩",
    "INR": "₹",
}


def format_cost(
    amount_usd: float,
    currency: str = "USD",
    exchange_rate: float = 1.0,
    precision: int = 4,
) -> str:
    """Format a USD cost amount in the target currency.

    Args:
        amount_usd: Cost in USD.
        currency: ISO 4217 currency code.
        exchange_rate: Multiplier to convert USD → target currency.
        precision: Decimal places.

    Returns:
        Formatted string like "$1.2345" or "€1.1234".
    """
    converted = amount_usd * exchange_rate
    symbol = CURRENCY_SYMBOLS.get(currency, currency + " ")
    return f"{symbol}{converted:.{precision}f}"

Step 2: Add config fields

In src/bernstein/core/models.py, add to OrchestratorConfig (around line 1024, near budget_usd):

currency: str = "USD"
currency_exchange_rate: float = 1.0

Step 3: Replace hardcoded $ formatting

In src/bernstein/cli/cost.py, replace all f"${amount:.Xf}" with format_cost(amount, cfg.currency, cfg.exchange_rate, precision=X).

Example before:

cons.print(f"  Bernstein     [green]{bar}[/green]  [bold green]${actual_cost:.4f}[/bold green]")

After:

from bernstein.core.cost import format_cost
cons.print(f"  Bernstein     [green]{bar}[/green]  [bold green]{format_cost(actual_cost, currency, rate)}[/bold green]")

Step 4: Add config to bernstein.yaml template

In templates/bernstein.yaml:

# Currency for cost display (default: USD)
# currency: EUR
# currency_exchange_rate: 0.92

Step 5: Write tests

# tests/unit/test_cost_format.py
from bernstein.core.cost import format_cost


def test_format_usd_default():
    assert format_cost(1.5) == "$1.5000"


def test_format_eur():
    assert format_cost(1.0, currency="EUR", exchange_rate=0.92) == "€0.9200"


def test_format_gbp_precision_2():
    assert format_cost(10.0, currency="GBP", exchange_rate=0.79, precision=2) == "£7.90"


def test_format_unknown_currency():
    assert format_cost(5.0, currency="BTC", exchange_rate=0.000015) == "BTC 0.0001"

Step 6: Run tests

uv run pytest tests/unit/test_cost_format.py -x -q

Acceptance criteria

  • format_cost() function in src/bernstein/core/cost.py
  • Config fields currency and currency_exchange_rate in OrchestratorConfig
  • All $X.XX formatting in cost.py uses format_cost()
  • Tests pass
  • Pyright strict passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Priority 2 - Normalbeginner-friendlyDetailed implementation guide includedcostCost tracking and budgetingenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededpythonPython

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions