feat: per-key spend accounting and per-task complexity pinning
API keys page: the table now answers "which department spends what" — per-key requests, tokens in/out and cost for a selectable window (24h/7d/30d) plus a cumulative all-time cost column, joined from stats by the key's account. The stats log stays bounded while the accounting survives: once stats.jsonl exceeds max_file_mb (default 16, 0 disables), records older than the retention window fold into cumulative per-account totals in a small sidecar file (tmp+rename on both) and leave the log. alltime = folded + in-file, a record is never counted twice, verified end-to-end on synthetic data (1.2 MB → 301 KB, totals identical before/after compaction and restarts). Routing: a task rule can now PIN the complexity tier — `[routing.tasks.legal] models=[...] tier="high"` (old plain-array rules parse unchanged). The pinned tier replaces the router's verdict before the escalation check and reports itself as route_source "router+task-rule@high". The Routing page grows a per-task «Complexity» selector (Auto/low/medium/ high); verified live: a code prompt with a pinned high went router+task-rule@high → the expensive model. 13 new strings in all 7 languages; docs/ROUTING(.ru) updated.
This commit is contained in:
+13
-6
@@ -232,15 +232,22 @@ impl Pipeline {
|
||||
match live.router.route(&text, prof).await {
|
||||
Ok(Some(dec)) => {
|
||||
let src = dec.source.clone();
|
||||
let (cands, task_rule) = live
|
||||
let mut dec = dec;
|
||||
let (cands, task_rule, forced) = live
|
||||
.routing
|
||||
.candidates_for(&dec.task_label, &dec.complexity_tier);
|
||||
// surface which rule chose the head of the chain
|
||||
let src = if task_rule {
|
||||
format!("{src}+task-rule")
|
||||
} else {
|
||||
src
|
||||
// surface which rule chose the head of the chain,
|
||||
// and when the rule pinned the complexity —
|
||||
// "…+task-rule@high" — reflect it in the
|
||||
// decision so headers/stats tell the truth
|
||||
let src = match (task_rule, &forced) {
|
||||
(true, Some(tier)) => format!("{src}+task-rule@{tier}"),
|
||||
(true, None) => format!("{src}+task-rule"),
|
||||
_ => src,
|
||||
};
|
||||
if let Some(tier) = forced {
|
||||
dec.complexity_tier = tier;
|
||||
}
|
||||
(dec, src, cands)
|
||||
}
|
||||
Ok(None) | Err(_) => {
|
||||
|
||||
Reference in New Issue
Block a user