1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//! # llm-budget-window
//!
//! Time-windowed token + USD budget for LLM calls.
//!
//! [`token-budget-pool`](https://crates.io/crates/token-budget-pool) caps
//! total spend across concurrent tasks. This crate adds a time axis:
//! cap spend per minute, per hour, per day, or any combination. Each
//! recorded call is timestamped; older entries fall out of the window
//! automatically.
//!
//! ## Quick example
//!
//! ```
//! use std::time::Duration;
//! use llm_budget_window::{BudgetWindows, Window, WindowBreached};
//!
//! let bw = BudgetWindows::new(vec![
//! Window::new("per_minute", Duration::from_secs(60))
//! .with_token_cap(50_000)
//! .with_usd_cap(1.0),
//! Window::new("per_hour", Duration::from_secs(3600))
//! .with_usd_cap(10.0),
//! ]);
//!
//! // record consumption; raises if ANY window would breach
//! bw.record(tokens(1000), usd(0.05)).unwrap();
//!
//! // for very cheap calls, both windows have plenty of room
//! for _ in 0..50 {
//! let _ = bw.record(tokens(100), usd(0.001));
//! }
//!
//! # fn tokens(n: u64) -> u64 { n }
//! # fn usd(v: f64) -> f64 { v }
//! ```
//!
//! ## Memory
//!
//! Each window keeps a `VecDeque` of (timestamp, tokens, usd) records.
//! Old records age out on every `record()` and `snapshot()`. For very
//! high call rates, set windows you actually need - a 1-day window
//! holds every call from the last 24h.
pub use WindowBreached;
pub use ;