"""网关单测替身(mock provider + 内存 ledger)——不碰真实 API / DB。 放在独立模块(非 conftest)以便测试用绝对导入 `from fakes import ...`; 本目录无 __init__.py(避免与顶层 tests 包同名冲突),故走 pytest 路径注入。 """ from __future__ import annotations from collections.abc import AsyncIterator from ww_llm_gateway.adapters.base import ( Capabilities, ProviderResult, ProviderUsage, StreamChunk, ) from ww_llm_gateway.routing import Route from ww_llm_gateway.types import LlmRequest, Scope, Tier, Usage class FakeAdapter: provider = "deepseek" def __init__(self, text: str = "hello world", deltas: list[str] | None = None) -> None: self.text = text self.deltas = deltas if deltas is not None else ["hel", "lo ", "world"] self.complete_calls = 0 self.stream_calls = 0 def capabilities(self) -> Capabilities: return Capabilities(structured_output=True, prefix_cache=True) async def complete(self, req: LlmRequest, model: str) -> ProviderResult: self.complete_calls += 1 return ProviderResult( text=self.text, usage=ProviderUsage(input_tokens=100, output_tokens=50), ) async def stream(self, req: LlmRequest, model: str) -> AsyncIterator[StreamChunk]: self.stream_calls += 1 for d in self.deltas: yield StreamChunk(text=d) yield StreamChunk(usage=ProviderUsage(input_tokens=100, output_tokens=50)) class FakeLedger: def __init__(self) -> None: self.records: list[Usage] = [] async def record(self, scope: Scope, usage: Usage) -> None: self.records.append(usage) def fake_route(tier: Tier) -> Route: return Route(provider="deepseek", model="deepseek-chat")