feat: cost/quota set — dual-column priced reports, creator split, hard cutoff, approval-timeout auto-threshold

- CostStore: per-model breakdown, report_by_creator (JOIN tasks.created_by),
  dual-column reports with priced_usd_micros, unpriced_models listed
  separately and a billing note (proxy price, not the relay bill);
  _report itself untouched, old exact-key tests keep passing.
- Hard cutoff: cost.quota_cutoff_reason is the single USD/unpriced-cap
  decision; worker._quota_exceeded now delegates to it (identical
  messages); claim gate, turn boundary and poll kill stop spend and
  record interrupted + quota reason + audit; auto-resume re-checks
  live quota before requeueing.
- Approval timeout (G7 ops metric): cloud/approval_timeout.py —
  default stays 600s, >20% timeout rate recommends 1800s, <5% keeps,
  mid-range keeps; stats + recommendation + info log; wired into
  /metrics (member projects, no log spam) and a global-admin
  /admin/ops/approval-timeout endpoint (sweeps overdue first).
- Server: task/project cost endpoints return dual-column reports;
  new GET /users/me/cost and GET /admin/cost-by-creator.
- Tests: cloud/tests/test_cost_quota.py, 10 tests.
This commit is contained in:
host committed 2026-11-03 02:49:25 +00:00
1 parent 0072e1ae6a
commit 143ab30094
5 files changed
+871 -12

No files matched your search

+6 -10
View File
@@ -142,7 +142,7 @@ from cloud.coordinator import ensure_columns as _coord_ensure_columns
from cloud.coordinator import parse_parts as _coord_parse_parts
from cloud.coordinator import nonterminal_children as _coord_nonterminal
from cloud.cost import CostStore, estimate_tokens, price_usd_micros, \
sum_usage, unpriced_token_cap
quota_cutoff_reason, sum_usage
from cloud.db import connect as _db_connect
from cloud.goal_command import parse_goal_command as _parse_goal_command
from cloud.logging_config import get_logger, log_event, setup_logging
@@ -2155,15 +2155,11 @@ class Worker:
unpriced_used += (
max(0, int(usage_total.get("input_tokens", 0)))
+ max(0, int(usage_total.get("output_tokens", 0))))
if used >= quota:
return ("quota_exceeded: 本月配额已用完(已用 %d / "
"配额 %d 微美元,%s)" % (used, quota, month))
cap = unpriced_token_cap()
if unpriced_used >= cap:
return ("quota_exceeded: 本月无价模型 token 已用完"
"(已用 %d / 上限 %d,%s)"
% (unpriced_used, cap, month))
return None
# 硬切断判定收敛到 cost.quota_cutoff_reason:USD 配额与
# 无价上限任一超限即回 quota_exceeded 文本,调用方(认领
# 门、轮次边界、30 秒轮询)据此停掉任务、不再开新回合;
# 文本与旧分支逐字一致,旧单测按此前缀断言。
return quota_cutoff_reason(quota, used, unpriced_used, month)
def _ready_tasks(self):
"""当前就绪任务列表(pick_next 的批量版)。