Repository navigation
Conversation
A standard run's cost estimate came from 13 OpenAI models written in run.py, matched by name prefix. The list is now the user's: fetched on request from a public list, with the user's own rows over it, and a model is priced by exactly its name. A run never fetches a price.
# Conflicts: # app/nullius/standard/run.py
…list never prices a run
…n, turning while it updates
A job's config.json credited the public list (its address and day) with every recorded price, including a row of the user's own and a run's --price. Each row now carries its source (list, own, run), and the list is named only when a row is its. A refused update repeated its address or file in the message.
nullius standard run --max-usd USD: every relay of the job, the units' own in this process or in their containers and the benchmark's, books each call in one ledger before sending it. A call is sent only while what was spent, what the calls in flight have booked and its own booking stay within the cap. The first that does not fit is refused by the relay itself (HTTP 402, recorded as refused, never as the provider's error), and so is every call after it. A unit cut off ends as SpendingCapError, an API error outside the agent's rate. Units not begun are not run. result.json carries the cap, what was spent, whether it stopped the run, the units cut off and those not run. A capped run is refused before it starts when a model it calls has no price.
# Conflicts: # app/nullius/standard/container.py # app/nullius/standard/relay.py # app/tests/test_standard_relay.py
This comment has been minimized.
This comment has been minimized.
1 of 9 tasks
A unit the run's cap cut off read as an API error, as if the provider had failed. Nothing failed: the relay refused the call at the user's own cap. It is now the outcome spending_cap (Spending cap), outside the adjusted rate like the other infrastructure outcomes, in a bronze of its own in both themes. On the live feed it is budget, an outcome the board already knew and nothing produced; the board's adjusted rate leaves it out as it does infra_error. The judge is not offered it as a likely outcome and no cause suggests it: only the relay's refusal makes it, recorded, never read from a transcript.
This comment has been minimized.
This comment has been minimized.
A workspace caches parsed jobs by the parse's schema. A unit the cap cut off now classifies as spending_cap where it read api_error, so a cache written by the earlier parse would be read back as current: the schema moves to 13.
This comment has been minimized.
This comment has been minimized.
A call was booked at the model's whole output limit when it named none. On a real provider that was 0.026 USD for calls that cost 0.0002: fifteen problems at a time under a 0.30 USD cap sent eleven calls and stopped with 0.002 spent. What was spent was already each reply's real cost. Only a call in flight has to be estimated, since its cost is known when its reply comes back. It is now counted as the largest reply the run has had from that model so far, which the ledger keeps, and as 4,096 output tokens before any reply; never more than the limit the call names or the model's own.
This comment has been minimized.
This comment has been minimized.
# Conflicts: # app/nullius/standard/cli.py # app/nullius/standard/run.py # app/tests/test_standard_run.py # docs/cli/run.md # docs/settings/model-prices.md
🔴 PR judge · 6 of 8 yes · #46 ↔ #14
Acceptance criteria, 2 of 2 met
Checks the script runs itself, 4 of 4 pass
some of the diff was cut before the judge read it |
Collaborator
Author
2 of 9 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #14
What
nullius standard run --max-usd USDstops a run at a spending cap. Every relay of the job (the units' own, in this process or in their containers, and the benchmark's) books each call in one ledger before sending it (app/nullius/standard/ledger.py). What was spent is each reply's real cost; only a call in flight is an estimate, since its cost is known when its reply comes back: the call's characters over three as input tokens, and as output the largest reply the run has had from that model so far, which the ledger keeps, or 4,096 tokens before any reply, never more than the limit the call names or the model's own, at the user's prices. A call is sent only while what was spent, what the calls in flight have booked and its own booking stay within the cap. The first that does not fit is refused by the relay itself (HTTP 402, a body and a header that name the relay, recordedrefused), and so is every call after it, so a run stops at one point. A reply turns the booking into what the call cost; a provider's error gives it back; a reply with no token count, or cut off, keeps the whole booking as unsettled.A unit the cap cut off ends as
SpendingCapError, an outcome of its own:spending_cap(Spending cap), outside the agent's rate like the infrastructure outcomes, never a miss, in a bronze of its own in both themes. Nothing failed, so it is no longer read as an API error. On the live feed it isbudget, an outcome the board already knew and nothing produced. The judge is not offered it and no cause suggests it: only the relay's refusal makes it. The parse's cache schema moves to 13, so a job cached with the earlier reading is read again. Units not begun are not run.result.jsoncarriesbudget:max_usd,spent_usd,unsettled_usdwhen there is some,stopped,cut_offandnot_run. A capped run is refused before it starts when a model it calls has no price.Not in this change: the cap in the builder and on a host, shared over a run's jobs and shards, and the job page showing the budget (#45, in #48); a cap per unit (#47).
Built on #39 (the user's price list), which is on
mainnow;mainis merged into this branch, so the diff is the cap alone.Touches
backend · templates and static · docs and site · the standard
Before and after
The job page of a run its cap stopped, at 1400 px in the dark theme; the images are not attached here.
Verified
app/tests/test_standard_ledger.py(10 tests): a call is sent while spent, in flight and its booking fit; the first that does not fit closes the ledger for every later one; an unknown cost keeps its booking and an error gives it back; a ledger that cannot be read lets no call out; 60 calls at once never book past the cap; four processes booking in one ledger lose nothing; what a booking is (the named limit, the model's own, the default, cache-write input, embeddings, an encoded file not counted).test_standard_relay.py: a call that fits is sent and settled at its cost; one that does not is answered 402 by the relay, marked, recordedrefusedand never reaches the provider, and neither does a smaller one after it; a provider's 429 gives the booking back; a reply without tokens keeps it; a model without a price is not sent; a relay without a cap books nothing; the relay as a process of its own books in the ledger it is given.test_standard_run.py: eight units under a cap the fourth call does not fit: three run, one is cut off (SpendingCapError, the outcomespending_cap), four are not run,result.jsonsays so and no call went out past the cap; an ample cap changes nothing but the result; no cap, no ledger; a cap without a price for each model, or with a bad amount, is refused before anything is begun.test_classify.py: the cut-off unit has its own outcome, outside the rate, for the classifier and the live board (budget).test_outcome_styles.py,test_field_guide.py,test_judge.pyandtest_reconcile.pyhold the new outcome to a colour in both themes, a row in the field guide and a place in the judge's table.test_standard_container.py: the relay's container is given the ledger and its folder alone.python3 app/tests/parallel.py(1657 tests) and route suite (356 tests), OK, aftermainwas merged in and again with the outcome.docs-driftscript: 0 findings.gpt-4o-miniat list price, 0.00024 USD a call, booked 0.0099):--max-usd 0.011: five ran, the sixth was cut off, four were not run, 0.0012 spent, as computed by hand;--backend docker, on the merged code: the containers' relays share the ledger; three ran, one was cut off, two were not run;--price: the run ended and the result carries what was spent;--max-usd 2: all ran, each call's cost taken from the provider's reply; the ledger counted 0.0008868 USD and the provider billed 0.0008868;Risk
--max-usd; without it no ledger exists and no call is booked.flockon a file beside the ledger, as an install is locked. On Docker Desktop a benchmark's own relay (an option's embeddings) runs on the machine while the units' relays run in the VM; whether the lock holds between the two was not tested.--priceor an own price.Undone by a revert; a job written with
budgetin its result stays readable.