Skip to content

Model prices are a table in the code: OpenAI only, and fixed between releases #38

Description

@aitianshi

Priority

extreme

Components

  • app/nullius (backend)
  • app/web (routes)
  • templates and static files
  • docs and the site
  • catalogue (benchmarks, agents, capabilities)
  • the standard (ports, kits, relay, runs)
  • CI, workflows and skills

Today

A standard run's cost estimate comes from a table written in the code, run.py:86:

PRICES = {
    "gpt-5-mini": {"input": 0.25, "cached": 0.025, "output": 2.0},
    ...
    "text-embedding-ada-002": {"input": 0.1, "cached": 0.1, "output": 0.0},
}

It holds 13 OpenAI models and nothing else, so a run sent directly to another provider has no cost unless the reply carries one (OpenRouter's does). The numbers change only with a release. A model missing from it is priced by the first entry its name starts with (relay.py:383), so gpt-4.1-nano is priced as gpt-4.1. A user cannot add or correct a price.

Wanted

Prices are the user's data, not the code's, for anyone who reads a run's cost or wants to bound it.

  • One price list in the user's configuration: per model, as its provider names it, the input, cached input, cache write and output prices per million tokens and the model's output limit.
  • Filled on request from a public list keyed by the providers' own model names (LiteLLM's model_prices_and_context_window.json), from Settings and from the CLI, with its source and date kept. Never fetched during a run.
  • A user's own price for a model wins over the list; --price MODEL=INPUT,OUTPUT[,CACHED] prices one run.
  • A call's cost: the provider's own figure when its reply carries one, else the price of exactly that model name, else none.
  • No price ships with Nullius: a new profile shows no estimate until its list is filled once.

Acceptance

  • No price is written in the code: run.PRICES is gone and a new profile has no prices.
  • nullius prices update fills the user's price list from the public list, with its source and date, and Settings has the same action; a run never fetches it.
  • A user's own price for a model (nullius prices set, --price on a run) wins over the list, and can be removed.
  • A call is priced by its exact model name or not at all: no prefix match.
  • A run in docker or on a host is priced from the list of the machine that started it.
  • A job's config.json records the prices it was given and where the list came from.
  • The field guide, the Settings guide and the CLI pages say where an estimate's price comes from.

Dependencies and related

#14 (a spending cap) waits on this: a cap needs a price for every model a run calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions