Skip to content

v0.8.45 provider billing: audit cost math and add /balance command #2019

@Hmbown

Description

@Hmbown

Context

Now that sub-agents and long-running work are becoming more reliable, CodeWhale should audit whether its money/cost calculations are logically correct. Users should also have a simple way to ask the active provider what their real account balance/credits are, where the provider exposes an official endpoint.

Do not assume every provider supports this. Implement /balance as a provider capability: supported providers return structured balance data; unsupported providers return a clear "balance check not supported for this provider" message.

Official endpoints verified so far

  • DeepSeek documents GET https://api.deepseek.com/user/balance, returning is_available plus balance_infos[] with currency, total_balance, granted_balance, and topped_up_balance.
  • OpenRouter documents GET https://openrouter.ai/api/v1/credits, returning total credits purchased and total usage. Docs note a management key is required.
  • Novita AI's official API index lists Get User Balance under Basic APIs, for account balance queries.

Do not ship other providers until their official docs are checked. Some providers may expose billing only through dashboards or organization-level APIs.

Scope

Add a provider-account/billing capability layer and a /balance slash command.

The command should support:

  • active provider by default: /balance
  • explicit provider: /balance deepseek, /balance openrouter, /balance novita
  • clear unsupported state for providers without a known balance endpoint
  • safe error handling for missing API keys, auth failures, insufficient scopes, and network errors
  • no API key leakage in logs, errors, or copied receipts

Suggested architecture

Introduce a provider balance capability, separate from chat completions:

trait ProviderBalanceClient {
    fn provider_id(&self) -> ProviderKind;
    async fn fetch_balance(&self, auth: ProviderAuth) -> Result<ProviderBalance, BalanceError>;
}

struct ProviderBalance {
    provider: ProviderKind,
    is_available: Option<bool>,
    currency: Option<String>,
    total_balance: Option<String>,
    granted_balance: Option<String>,
    topped_up_balance: Option<String>,
    total_credits: Option<f64>,
    total_usage: Option<f64>,
    remaining_credits: Option<f64>,
    source: BalanceSource,
    checked_at: SystemTime,
}

This can be shaped to match existing provider abstractions; the important part is that balance/credits support is a capability, not assumed for every OpenAI-compatible provider.

Cost accounting audit

In the same workset or a tightly linked follow-up, audit CodeWhale's estimated spend logic:

  • prompt/input token cost
  • output token cost
  • reasoning token cost, if billed/reported separately
  • cache hit vs cache miss input pricing
  • provider-specific pricing tables
  • sub-agent child usage aggregation
  • RLM/agent child calls
  • failed/cancelled/stream-interrupted calls
  • retries and duplicate sends
  • currency display and CNY/USD conversion assumptions

The audit should distinguish:

  • provider-reported usage
  • CodeWhale-estimated usage
  • provider account balance/credits from /balance

Do not present estimated cost as exact provider billing unless we can reconcile it with provider-reported data.

DeepSeek-specific acceptance criteria

  • /balance deepseek calls GET https://api.deepseek.com/user/balance with bearer auth.
  • The response displays is_available, currency, total balance, granted balance, and topped-up balance.
  • Missing key, 401/403, and network failures produce actionable errors.
  • The command works with existing DeepSeek provider config and env vars.
  • No API key or bearer token appears in logs, transcript, task receipts, or copied details.

OpenRouter-specific acceptance criteria

  • /balance openrouter calls the official credits endpoint if the configured key has the required management scope.
  • Display total credits, total usage, and remaining credits when derivable.
  • If the key lacks required scope, explain that the endpoint requires the appropriate OpenRouter key permissions.

Generic UX acceptance criteria

  • /balance defaults to the active provider.
  • Unsupported providers return a clear not-supported message and suggest checking the provider dashboard.
  • The command is explicit user-invoked network I/O; do not poll balances in the background unless a separate opt-in issue exists.
  • Balance results are copyable/inspectable like other tool receipts.
  • If the active model routes through an aggregator, show the aggregator balance, not the upstream model creator's balance.

Tests

  • Unit tests for DeepSeek balance response parsing.
  • Unit tests for OpenRouter credits response parsing.
  • Unit tests for unsupported-provider behavior.
  • Tests for missing API key and auth failure formatting.
  • Cost-accounting tests for sub-agent usage aggregation and cache hit/miss pricing assumptions.

Documentation

Update docs/settings or a provider diagnostics doc with:

  • /balance examples.
  • Which providers are supported.
  • Why unsupported providers cannot be checked programmatically.
  • Difference between estimated session cost and provider account balance.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions