# llm-rotator — Project Instructions

**Never hallucinate or fabricate information. If you're unsure about anything, you MUST explicitly state your uncertainty. Say "I don't know" rather than guessing or making assumptions. Honesty about limitations is required.**

## Project Overview

`llm-rotator` — Python-библиотека для отказоустойчивой ротации LLM-провайдеров. Circuit breaker, квоты, model-first маршрутизация. Async-first, Python 3.11+.

## Key Files

- `docs/PRD.md` — Product Requirements Document
- `docs/IMPLEMENTATION_PLAN.md` — Детальный план реализации MVP (все фазы завершены)
- `docs/IMPLEMENTATION_PLAN_V2.md` — План реализации V2 (все фазы завершены)
- `src/llm_rotator/` — исходный код пакета
- `tests/` — тесты (unit, integration, e2e)

## Tech Stack

- **Python:** 3.11+
- **Build:** uv + hatchling
- **Dependencies:** pydantic v2, httpx
- **Optional deps:** redis[asyncio] (Redis backend), langchain-core (LangChain integration)
- **Testing:** pytest, pytest-asyncio, respx (httpx mock), freezegun, fakeredis
- **Linting:** ruff
- **CI:** GitHub Actions

## Commands

```bash
# Установка зависимостей
uv sync --dev

# Запуск unit + integration тестов
uv run pytest tests/unit tests/integration -v

# Запуск e2e (требует API ключи в env)
uv run pytest tests/e2e -m e2e -v

# Линтер
uv run ruff check src/ tests/
uv run ruff format src/ tests/

# Покрытие
uv run pytest --cov --cov-report=term-missing

# Сборка пакета
uv build
```

## Architecture Conventions

- **Exceptions** бросают клиенты (`clients/`), а не ротатор. Ротатор ловит и маршрутизирует.
- **State Backend** — абстракция (ABC). Реализации: InMemoryBackend (default), RedisBackend (multi-instance).
- **LLM Client** — абстракция (ABC). Реализации: OpenAIClient, GeminiClient, AnthropicClient.
- **LifecycleHook** — `typing.Protocol`, не ABC. Partial implementation OK.
- **Config** — Pydantic v2 модели. Программная конфигурация (dict / model) + JSON файл с env substitution.
- **Injectable clock** в InMemoryBackend для тестируемости TTL.
- **Model-First CoR** — для каждой модели перебираются все ключи, прежде чем даунгрейд.
- **Tier Ceiling** — `tier` (1=лучший) в `RoutingContext` ограничивает сверху; ротация только вниз.
- **Streaming** — mid-stream error → retry с начала на следующем кандидате.
- **Tool Calling** — единый OpenAI-совместимый формат tools, трансляция под капотом для каждого провайдера.
- **Structured Logging** — полная цепочка маршрутизации в одной строке лога.
- **Quota Warnings** — callback + lifecycle hook при пересечении порога (default 80%).
- **LangChain** — `RotatorChatModel(BaseChatModel)` — drop-in для chains/agents. Опциональная зависимость.

## Naming

- Исключения: `*Error` (не `*Exception`)
- Модули: snake_case
- Конфиг-модели: `*Config`
- ABC: `Abstract*`

## What NOT to do

- Не добавлять provider SDK (openai, anthropic, google-genai) — только httpx
- Не добавлять YAML/TOML парсинг конфига
- Не коммитить API ключи — только через env vars
