refactor: 调度器迁移至独立模块,消除 services->api 反向依赖

- 将调度器相关模块从 src/services/cache/ 迁移到 src/services/scheduling/
- 下沉类型定义到 core 层: AccessRestrictions, ProviderAuthInfo, ParsedChunk/StreamStats, 视频工具函数
- 提取 thinking_cache 签名缓存到 core/api_format/conversion/
- 提取 provider 认证逻辑到 services/provider/auth
- 提取遥测记录到 services/usage/telemetry
- 提取 models 列表缓存到 services/cache/model_list_cache
- 更新所有引用方的 import 路径及相关测试
This commit is contained in:
fawney19
2026-02-16 11:00:48 +08:00
parent 4dc401677d
commit 63870931af
85 changed files with 1907 additions and 1463 deletions

View File

@@ -1,13 +1,14 @@
from __future__ import annotations
from types import SimpleNamespace
from typing import Any
from typing import Any, cast
from unittest.mock import AsyncMock, MagicMock
import pytest
from src.services.cache.aware_scheduler import CacheAwareScheduler, ProviderCandidate
from src.models.database import Provider, ProviderAPIKey, ProviderEndpoint
from src.services.orchestration.candidate_resolver import CandidateResolver
from src.services.scheduling.aware_scheduler import CacheAwareScheduler, ProviderCandidate
class _FakeScheduler:
@@ -89,19 +90,19 @@ def _make_global_key_candidate(*, key_id: str, priority: int) -> ProviderCandida
global_priority_by_format={"openai:chat": priority},
)
return ProviderCandidate(
provider=provider,
endpoint=endpoint,
key=key,
provider=cast(Provider, provider),
endpoint=cast(ProviderEndpoint, endpoint),
key=cast(ProviderAPIKey, key),
needs_conversion=False,
provider_api_format="openai:chat",
) # type: ignore[arg-type]
)
@pytest.mark.asyncio
async def test_candidate_resolver_pagination_continues_on_empty_candidate_batch() -> None:
db = MagicMock()
scheduler = _FakeScheduler()
resolver = CandidateResolver(db=db, cache_scheduler=scheduler) # type: ignore[arg-type]
resolver = CandidateResolver(db=db, cache_scheduler=cast(CacheAwareScheduler, scheduler))
candidates, global_model_id = await resolver.fetch_candidates(
api_format="openai:chat",