pub struct Budget {
pub tokens: Option<u64>,
pub usd: Option<Decimal>,
pub wall: Option<Duration>,
pub calls: Option<u32>,
}Expand description
What a node is permitted to spend, in whichever units were declared.
Any subset of the four may be set. A unit left as None is unbounded in
that unit — it does not weaken the units that were declared.
§Example
use boundgraph_core::Budget;
use std::time::Duration;
let b = Budget::UNBOUNDED
.with_usd("0.50".parse().unwrap())
.with_wall(Duration::from_secs(30));
assert!(!b.is_unbounded());
assert_eq!(b.tokens, None); // tokens were never bounded
assert_eq!(b.declared_units(), ["usd", "wall"]);Fields§
§tokens: Option<u64>Total tokens, prompt plus completion.
usd: Option<Decimal>Spend in US dollars.
A decimal, never a float: money that round-trips through f64 stops
being auditable, and the ledger is meant to be audited.
wall: Option<Duration>Wall-clock time.
calls: Option<u32>Number of model calls.
Implementations§
Source§impl Budget
impl Budget
Sourcepub const UNBOUNDED: Self
pub const UNBOUNDED: Self
No limit in any unit.
The default, and deliberately something you have to name — see the module documentation.
Sourcepub fn with_tokens(self, tokens: u64) -> Self
pub fn with_tokens(self, tokens: u64) -> Self
Bound the token count.
Sourcepub fn with_usd(self, usd: Decimal) -> Self
pub fn with_usd(self, usd: Decimal) -> Self
Bound the spend.
The amount is normalised, so 1.50 and 1.5 are the same budget and
therefore encode to the same bytes and the same digest.
Sourcepub fn with_calls(self, calls: u32) -> Self
pub fn with_calls(self, calls: u32) -> Self
Bound the number of model calls.
Sourcepub fn is_unbounded(&self) -> bool
pub fn is_unbounded(&self) -> bool
Whether nothing at all is bounded.
Sourcepub fn amount(&self, unit: Unit) -> Option<u64>
pub fn amount(&self, unit: Unit) -> Option<u64>
What this budget bounds in one unit, normalised to an integer.
Currency becomes micro-dollars and time becomes milliseconds — see the
module documentation for why there is one space to compare in. None
means this budget does not bound that unit, which is not the same as
bounding it at zero.
Sourcepub fn bounded_units(&self) -> Vec<Unit>
pub fn bounded_units(&self) -> Vec<Unit>
Which units this budget bounds, in a stable order.
Sourcepub fn excesses(&self, parent: &Self) -> Vec<Excess>
pub fn excesses(&self, parent: &Self) -> Vec<Excess>
Every unit in which this budget asks for more than parent permits.
Only units both budgets bound can be exceeded — see the module documentation for why the two asymmetric cases are legal. Returns them all rather than the first, in unit order.
Sourcepub fn fits_within(&self, parent: &Self) -> bool
pub fn fits_within(&self, parent: &Self) -> bool
Whether this budget can be declared beneath parent.
True when it claims no more than the parent has to give, in every unit they both bound.
Sourcepub fn clamped_to(&self, parent: &Self) -> Self
pub fn clamped_to(&self, parent: &Self) -> Self
This budget as it is actually enforced beneath parent.
The tighter of the two in every unit, which is the composition rule
itself: an effective ceiling is the smallest bound on the path down to
a node. Applying it to a budget that already
fits_within its parent returns that budget with
the parent’s bounds filled in where it declared none.
Idempotent, and associative down a chain: clamping to a parent and then to a grandparent gives what clamping straight to the tightest of the three would.
Sourcepub fn declared_units(&self) -> Vec<&'static str>
pub fn declared_units(&self) -> Vec<&'static str>
Which units this budget actually constrains, in a stable order.
Useful for diagnostics: “this flow bounds usd but not wall” is a
reviewable statement.