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:
@@ -179,6 +179,20 @@ A matching rule's models go **first** in the candidate chain; the complexity
|
||||
chain follows as fallback, so a task pin never weakens failover. Tasks without
|
||||
a rule route by complexity alone.
|
||||
|
||||
**Pinning complexity per task.** A task rule also accepts a full form with a
|
||||
forced tier — the router's verdict is replaced for that task before anything
|
||||
else happens:
|
||||
|
||||
```toml
|
||||
[routing.tasks.legal]
|
||||
models = ["strong-model"]
|
||||
tier = "high" # legal review is always high, whatever the router scored
|
||||
```
|
||||
|
||||
Responses whose tier was pinned report `route_source: "router+task-rule@high"`.
|
||||
The admin console's Routing page exposes this as a per-task «Complexity»
|
||||
selector (Auto / low / medium / high).
|
||||
|
||||
**Exception — high complexity escalates.** When the router rates a request
|
||||
`high` (and a `high` chain is configured), the tier chain leads and the task
|
||||
rule demotes to fallback. Otherwise a rule like `code → cheap-model` would pin
|
||||
|
||||
@@ -177,6 +177,20 @@ code = ["claude-sonnet", "gpt"] # код — сильнейшему ко
|
||||
сложности следует за ними как резерв — правило по задаче не ослабляет failover.
|
||||
Задачи без правила маршрутизируются только по сложности.
|
||||
|
||||
**Закрепление сложности за задачей.** Правило задачи принимает и полную форму
|
||||
с фиксированным уровнем — вердикт роутера для этой задачи заменяется до всех
|
||||
остальных шагов:
|
||||
|
||||
```toml
|
||||
[routing.tasks.legal]
|
||||
models = ["strong-model"]
|
||||
tier = "high" # юридические тексты — всегда high, что бы ни решил роутер
|
||||
```
|
||||
|
||||
Ответы с закреплённым уровнем сообщают `route_source: "router+task-rule@high"`.
|
||||
На вкладке Роутинг это селектор «Сложность» у каждой задачи (Авто / low /
|
||||
medium / high).
|
||||
|
||||
**Исключение — высокая сложность эскалирует.** Когда роутер оценил запрос как
|
||||
`high` (и цепочка `high` настроена), цепочка уровня идёт первой, а правило
|
||||
задачи становится резервом. Иначе правило вида `code → дешёвая-модель`
|
||||
|
||||
Reference in New Issue
Block a user