falaw.reprice#

Re-quote a persisted falaw.Plan at today’s rates (falaw#60).

A CallPlan’s estimated_cost_usd is frozen at plan time. That is right — a quote is a statement about a moment — but rate tables move: falaw 0.0.46 re-quoted every premium LLM call tenfold upward, so a preview saved the day before under-quotes the run it is being used to price. Under-quoting is the one direction a cost gate must never err in.

Re-quoting cannot be done from application and arguments alone. The quantity hints that priced a call — a clip’s duration, a prompt’s token bound — are estimator-only and deliberately never enter the wire arguments, so they are not on the serialized call. falaw.CostBasis is where a plan_* records them, together with which rate table it consulted; this module is what reads one back:

>>> from falaw import plan_generate_image, Plan, reprice_plan
>>> plan = Plan(calls=(plan_generate_image("a tiger", consult_cache=False),))
>>> repriced = reprice_plan(plan)
>>> [c.status for c in repriced.calls]
['unchanged']
>>> repriced.plan.total_cost_usd == plan.total_cost_usd
True

Three rules, in order of importance:

  • Pure data. Nothing here touches the network or a billing API, exactly like plan_*. Re-pricing reads the committed tables and does arithmetic.

  • A plan with no basis is never assumed current. Such a call comes back as "no_basis" with its cost cleared to None. Keeping the frozen figure would be the bug this module exists to fix, dressed as a feature.

  • Unknown is unknown, never free. A basis whose model has left the catalogue, whose pricer is not registered, or whose table no longer prices it re-prices to None — which lights up falaw.Plan.has_unknown_costs and forces approval.

The per-call diff says which of those happened, and CallRepricing.basis_changed says whether the table moved underneath the quote — the audit answer the frozen number could never give.

Module Attributes

RepriceStatus

What re-pricing was able to say about one call.

CATALOGUE_PRICER

CostBasis.pricer for a call priced from a models.json record.

LLM_RATES_PRICER

CostBasis.pricer for a routed LLM call priced from llm_rates.json.

DFLT_PRICERS

The pricers falaw ships — one per rate table it owns.

Functions

catalogue_cost_basis(model_id, **quantities)

A falaw.CostBasis for a call priced from models.json.

llm_cost_basis(routed_model, *[, ...])

A falaw.CostBasis for a routed LLM call priced from the rate table.

reprice_plan(plan, *[, pricers])

Re-quote every call in plan against today's rate tables.

Classes

CallRepricing(*, index, call, old_cost_usd, ...)

The before/after for one call in a re-priced plan.

Pricer(*, quote, table[, version])

One pricing rule, and the table that backs it.

RepricedPlan(*, plan[, calls])

Result of reprice_plan() — the new Plan plus the per-call diff.

falaw.reprice.CATALOGUE_PRICER = 'model_catalogue'#

CostBasis.pricer for a call priced from a models.json record.

class falaw.reprice.CallRepricing(*, index, call, old_cost_usd, new_cost_usd, status, reason='', basis_changed=False)[source]#

Bases: object

The before/after for one call in a re-priced plan.

basis_changed: bool#

True when the rate table’s identity or version moved between the persisted basis and today’s — the audit answer to “did the price change because the table changed?”. Always False for "no_basis", which has nothing to compare against.

call: CallPlan#

The re-priced call — the same call with today’s estimated_cost_usd and a basis stamped with today’s table version.

property delta_usd: float | None#

new - old, or None when either side is unknown.

None rather than 0.0: a call that lost or gained its price did not move by zero, and a caller summing deltas must not be handed a number that says it did.

index: int#

Position in the original falaw.Plan.

new_cost_usd: float | None#

What today’s rates say, None for unknown or no-basis.

old_cost_usd: float | None#

What the persisted plan said, None if it said unknown.

reason: str#

Why, when the status is "unknown" or "no_basis". Empty otherwise.

status: Literal['unchanged', 'changed', 'unknown', 'no_basis']#

Which of the four cases this call fell into — see RepriceStatus.

falaw.reprice.DFLT_PRICERS: Mapping[str, Pricer] = {'llm_rates': Pricer(quote=<function _quote_from_llm_rates>, table='falaw/data/llm_rates.json', version=<functools._lru_cache_wrapper object>), 'model_catalogue': Pricer(quote=<function _quote_from_catalogue>, table='falaw/data/models.json', version=<functools._lru_cache_wrapper object>)}#

The pricers falaw ships — one per rate table it owns.

Keyed by falaw.CostBasis.pricer. A basis naming anything else re-prices as "unknown": an unrecognized rule is a reason to refuse a number, not to keep the old one.

falaw.reprice.LLM_RATES_PRICER = 'llm_rates'#

CostBasis.pricer for a routed LLM call priced from llm_rates.json.

class falaw.reprice.Pricer(*, quote, table, version=<function Pricer.<lambda>>)[source]#

Bases: object

One pricing rule, and the table that backs it.

The seam for a caller with their own numbers: build a Pricer closing over a reconciled rate table and pass pricers={\*\*DFLT_PRICERS, LLM_RATES_PRICER: mine} to reprice_plan(). The table / version pair is stamped onto the re-priced call’s basis, so the next audit can see which table produced which number.

table is also a gate, not just a label: a call whose basis names a different table is reported as unknown rather than re-quoted, so a row priced from your invoice is never silently re-quoted at falaw’s published rate (or the reverse). Give your Pricer the same table string the basis carries — falaw.llm_rates.CUSTOM_LLM_RATES_TABLE for anything a plan_* priced with llm_rates=.

quote: Callable[[CostBasis], float | None]#

Price basis in USD, or return None for unknown. May raise; a raise is reported as "unknown" with the exception text as the reason, so one unpriceable row never aborts a whole plan’s re-quote.

table: str#

Identity of the table this pricer reads, for the refreshed basis.

version: Callable[[], str]#

Today’s version of that table, for the refreshed basis.

falaw.reprice.RepriceStatus#

What re-pricing was able to say about one call.

  • unchanged: re-quoted, and today’s rates give the same number.

  • changed: re-quoted to a different number — the interesting case.

  • unknown: a basis was present but could not be re-quoted — the model has left the catalogue, no pricer is registered under that name, the table no longer prices it, or the basis names a different table than the pricer reads (two sets of books do not re-quote each other). The new cost is None.

  • no_basis: the call carries no falaw.CostBasis at all — it was planned before falaw#60, or by something that never recorded one. The new cost is None, because the honest answer to “what does this cost today?” is that nobody can tell.

alias of Literal[‘unchanged’, ‘changed’, ‘unknown’, ‘no_basis’]

class falaw.reprice.RepricedPlan(*, plan, calls=())[source]#

Bases: object

Result of reprice_plan() — the new Plan plus the per-call diff.

Read plan for the re-quoted plan (it is an ordinary falaw.Plan, so known_cost_usd / unknown_call_count / has_unknown_costs mean what they always mean), and calls for what changed and why.

calls: tuple[CallRepricing, ...]#

One entry per call of the input plan, in order.

property changed: tuple[CallRepricing, ...]#

Calls whose price moved — the ones a re-quote exists to surface.

property known_delta_usd: float#

Sum of CallRepricing.delta_usd over calls priced both times.

The movement you can actually see. It says nothing about the calls in unpriced — read that alongside it, never this alone.

plan: Plan#

The re-priced plan. Structurally identical to the input — same calls, same order, same arguments, so plan_hash is unmoved — with today’s costs.

property unpriced: tuple[CallRepricing, ...]#

"unknown" plus "no_basis".

A budget gate refuses while this is non-empty, the same way it refuses on falaw.Plan.has_unknown_costs — the two are the same judgement, one made at re-quote time.

Type:

Calls today’s rates cannot price

falaw.reprice.catalogue_cost_basis(model_id, **quantities)[source]#

A falaw.CostBasis for a call priced from models.json.

quantities are falaw.estimate_call_cost() keywords (count, seconds, megapixels, tokens); None values are dropped, so a hint that was never supplied is recorded as absent rather than as null — the same thing the estimator saw.

Return type:

CostBasis

>>> catalogue_cost_basis("fal-ai/flux/dev", seconds=None).quantities
{}
falaw.reprice.llm_cost_basis(routed_model, *, input_tokens=None, max_output_tokens=None, custom_rates=False)[source]#

A falaw.CostBasis for a routed LLM call priced from the rate table.

custom_rates=True records that the quote came from a caller-supplied rates= table rather than the committed one: there is no file to digest, so the version stays empty and the table names itself falaw.llm_rates.CUSTOM_LLM_RATES_TABLE. reprice_plan() then refuses to re-quote it with the committed table, reporting unknown — a caller’s reconciled $0.50 row re-priced at falaw’s published $0.01 is a 50x under-quote, not a price drop. Re-quote it by passing a Pricer over your table that names that same identity.

Return type:

CostBasis

falaw.reprice.reprice_plan(plan, *, pricers={'llm_rates': Pricer(quote=<function _quote_from_llm_rates>, table='falaw/data/llm_rates.json', version=<functools._lru_cache_wrapper object>), 'model_catalogue': Pricer(quote = <function _quote_from_catalogue>, table='falaw/data/models.json', version=<functools._lru_cache_wrapper object>)})[source]#

Re-quote every call in plan against today’s rate tables.

Pure data: no network, no billing API, nothing executed. Returns a new RepricedPlan — the input plan is untouched.

A call carrying a falaw.CostBasis is re-quoted through the pricer its basis names, with the exact quantity hints that produced the original figure, and comes back with a basis re-stamped to today’s table version. A call carrying no basis is reported as "no_basis" and its cost is cleared to None: the frozen number is a fact about a past moment, and silently re-presenting it as a current quote is the failure this function exists to prevent. That clearing lights up falaw.Plan.has_unknown_costs, which is exactly right — nobody can say what that call costs today.

A basis is only re-quoted by a pricer reading the same table it names. A mismatch is "unknown", not a re-quote: two tables are two sets of books, and pricing a caller’s reconciled $0.50 row at falaw’s published $0.01 would be a 50x under-quote wearing the clothes of a price drop. Pass a Pricer naming that table to re-quote against the same books.

cache_status is carried through unchanged. Re-pricing answers “what would this cost?”, not “is it still cached?”; peeking the cache here would quietly turn a re-quote into an I/O operation and make a hit look like a price drop. Re-plan the calls if you want a fresh cache reading.

Parameters:
Return type:

RepricedPlan

>>> from falaw import Plan, CallPlan, reprice_plan
>>> stale = CallPlan(tool="generate_image", application="fal-ai/flux/dev",
...                  arguments={"prompt": "a tiger"}, output_kind="image",
...                  estimated_cost_usd=0.025)
>>> out = reprice_plan(Plan(calls=(stale,)))
>>> out.calls[0].status
'no_basis'
>>> out.plan.calls[0].estimated_cost_usd is None   # unknown, not $0.025
True
>>> out.plan.has_unknown_costs
True