0.167.26
Added
- Фоллбэк-цепочка моделей при сбое провайдера ( — P1). У каждой LLM-модели — упорядоченный список моделей-фоллбэков (
models.fallback_model_ids, JSON-массив ID, миграция 107 SQLite+PG): строкаmodelsуже кодирует пару (провайдер, модель), поэтому одна цепочка покрывает и фоллбэк по моделям, и по провайдерам (по образцу ZeroClaw reliable.rs / GoClaw failover.go). Рантайм:providers.FallbackProvider(обёрткаLLMProvider) на неудаче цели идёт к следующей — как по transient (rate limit на primary — главный сценарий), так и по permanent-ошибкам; внешний retry-слой (ChatStreamWithRetry) продолжает повторять всю цепочку с бэкоффом (Tier 3), так что все ~15 call-site’ов (react, heartbeat, memory, dream, kg, autocompact…) получают failover автоматически черезAgentLoop.resolveFromModelбез правок. Сквозные исключения: context overflow возвращается немедленно на emergency compact (#297 — обрезка внутри ретраев дублировала бы существующую механику), отмена/дедлайн контекста — наружу без обхода целей; стриминг переключается только до первого отправленного события (после — как есть, иначе дублирование вывода), брошенный канал передаётся drainer-горутине, чтобы producer провайдера не завис на блокирующей посылке. Сборка цепочки (AgentLoop.buildFallbackTargets): пропуск disabled/не-LLM/удалённых целей с WARN (мёртвая ссылка не валит primary), self/dedup, лимит 32 цели, учёт отмены ctx. Хранение: колонка + CRUD roundtrip в обоих сторах,ParseFallbackModelIDs. API: валидация вModelHandler(JSON-массив, существующие LLM-модели, без self/dublikatov, ≤32, канонический нормализованный вид). UI (/settings/models): секция «Фоллбэк-модели» с упорядоченными чипами (↑↓, ✕), выбором кандидатов и показом цепочки в карточке модели; повреждённые данные и очистка при смене типа на embedding — с явными предупреждениями. Тесты: Chat/ChatStream фоллбэки (transient/permanent/overflow/cancel/all-fail, committed-stream, connect-error, nil-error-event), сборка цепочки (7 видов пропуска), roundtrip+malformed, handler-валидация (valid/self/duplicate/unknown/embedding/длина), PG GetDefaultModel scan-арity после добавления колонки.