feat(pool,scheduling): 号池调度维度、配额冷却机制与管理后台重构

- 新增 scheduling_dimensions 模块,为每个 Key 计算多维调度状态(手动/冷却/熔断/成本/健康)
- 新增 quota_cooldown 模块,统一判定 Key 的有效冷却原因
- Pool 管理后台 API 扩展 Key 详情字段(调度状态/维度/配额/OAuth 信息)
- 前端 Pool 管理页面重写,支持调度状态展示、批量清理封禁 Key
- Handler 基类增加请求调度元数据采集,stream telemetry 增强
- 请求时间线组件增强,支持 attempted 候选展示
- Kiro OAuth 凭证导入解析改进
- 新增 usage 表 provider_key 索引迁移
- 补充调度维度、配额冷却、候选枚举等单元测试

Closes #197

Co-authored-by: AAEE86 <33052466+AAEE86@users.noreply.github.com>
This commit is contained in:
fawney19
2026-03-03 09:22:20 +08:00
parent f787b1b02a
commit 11997c024e
40 changed files with 4419 additions and 823 deletions

View File

@@ -166,6 +166,43 @@ async def test_trace_build_summary_matches() -> None:
assert summary["success_key_id"] == "key-3"[:8]
@pytest.mark.asyncio
async def test_trace_build_summary_uses_attempted_key_ids_when_provided() -> None:
pool = PoolManager("prov-1", PoolConfig())
c1 = _make_candidate("key-1")
c2 = _make_candidate("key-2")
with (
patch(
"src.services.provider.pool.redis_ops.get_sticky_binding",
new_callable=AsyncMock,
return_value=None,
),
patch(
"src.services.provider.pool.redis_ops.batch_get_cooldowns",
new_callable=AsyncMock,
return_value={"key-1": (None, None), "key-2": (None, None)},
),
patch(
"src.services.provider.pool.redis_ops.get_lru_scores",
new_callable=AsyncMock,
return_value={},
),
):
result = await pool.reorder_candidates(None, [c1, c2])
trace = getattr(result[0], "_pool_scheduling_trace", None)
assert trace is not None
summary = trace.build_summary(
success_key_id="key-1",
attempted_key_ids={"key-1"},
)
assert summary["total_keys"] == 2
assert summary["attempted"] == 1
assert summary["success_key_id"] == "key-1"[:8]
@pytest.mark.asyncio
async def test_sticky_trace_info() -> None:
pool = PoolManager("prov-1", PoolConfig(sticky_session_ttl_seconds=3600))