0.167.21
Fixed
- Детект переполнения контекста гейтился на HTTP 400 — Ollama/llama.cpp отдают 500, аварийная компакция не запускалась ( — P2).
IsContextOverflowErrorсканировал тело ошибки только приpe.StatusCode == 400, поэтому переполнение контекста на локальных бэкендах (Ollama/llama.cpp регулярно отвечают 500 с «context window»/«n_ctx» в теле) классифицировалось как транзиентная ошибка:spec.CompactFnне вызывался, а хуже —persistentRetryкрутил детерминированный отказ бесконечно. Фикс: единый статус-гейтовый сканclassifyContextOverflow(общий для Go-ошибок и error-ответов) с двумя наборами маркеров — strong (глагол+существительное:exceed(s) context window,n_ctx exceeded,maximum context length,prompt (is) too long,exceeds the maximum context,input length exceeds the context,exceeds the available context/exceeds context size(llama.cpp/Ollama),context length exceeded(проза-вариант маркера); доверяют только на явном наборе статусов, несущих решение бэкенда о запросе — {400, 413, 422, 500}: канонический 400, прокси-413, семантическая валидация 422 и прямой 500-ответ Ollama/llama.cpp; 429 и auth/routing 4xx (401/403/404/…) исключены — их тела это rate-limit словарь и отказы аутентификации/маршрутизации, 502/503/504 — прокси-бойлерплейт и эхо логов упавшего бэкенда) и weak (token limit,too many tokens,maximum number of tokens,token_limit,input length exceeds the maximum; только на каноническом 400 — 413 исключён, т.к. прокси отвечают им квотами; плюс reject-проверка co-occurrence rate-limit квалификаторов («per minute/second/hour/day»,tpm,rpm) — старые vLLM отвечали 400 на TPM-лимиты, и «input length exceeds the maximum per minute» не должно флипать в overflow). Структурный маркерcontext_length_exceededв Type/Code — на любом статусе, кроме 429 (429 дефиниционно rate limit — его backoff не должен skip’аться). Транспортные ошибки (StatusCode==0) body-скан не проходят вовсе. Plain-ошибки (без статуса) — только strong-маркеры. Ретрай-слой: во всех четырёх циклах (standardRetry/persistentRetry+ stream-варианты) переполнение не ретраится — возвращается сразу (Go-ошибка как есть; error-ответ конвертируется в*ProviderErrorс нормализованнымCode=context_length_exceeded, canonical-400 при пропавшем статусе, без тела в сообщении — no-leak,ShouldRetry=false), чтобы runner (runner.goemergency-compact) получил детерминированный сигнал вместо сожжённого бюджета попыток; body error-ответов сканируется с капом 4 KiB (обрезка по границе рун). Лог каждой шорткат-ветки (status_synthesizedдля triage). Тесты: положительные — 500+exceed context window/n_ctx =(Ollama/llama.cpp-стили), 413+strong, 400+context_length_exceeded(регресс), Anthropic «prompt is too long», response-ветка (Content-маркеры, статус 0 + структурный маркер), re-классификация возвращённой ошибки, end-to-end через retry-цикл (Chat + stream, ровно 1 вызов); отрицательные — 429+rate-limit словарь (включая «input length exceeds the maximum per minute»), 500+«internal server error», 500/413/422+weak, plain+weak, транспортный echo (status 0), биллинг-апселл «context window», 502/503/504+strong в теле прокси (эхо логов не флипает классификацию), 429+структурный маркер в Type, 400+«per minute»/tpm(rate-limit квалификаторы), 401/403/404/409+strong (auth/routing), nil; регресс — транзиент 503 по-прежнему ретраится до 3 попыток.