1.7.7
Fixed (#405)
- Image-части больше не уходят на wire text-only модели: litellm-прокси отвечал 400
messages.content.type is invalid, allowed values: ['text']на каждый ход диалога после первого сообщения с картинкой (прод: agent 1, glm-5.3 → fallback-цепочка glm-5.2/5.1, llm-логи~/.local/share/taigaclaw/llm-logs/1/*.jsonl— user-сообщение сparts:["image"]персистится вmessages.mediaи уезжало в каждом следующем запросе). Гейт способностей модели применялся только к вложениям из workspace; inline-медиа из WebSocket-канала, ре-гидрация истории из БД и сериализация обоих провайдеров шли без проверки. НовыйChatRequest.ImageInputAllowed *bool: агент резолвит вердикт полным каскадом (overridemodels.supports_vision→ реестр capabilities — реестр в провайдере напрямую НЕ читается, чтобы не ломать легитимный override на кастомных litellm-группах) при сборке хода (основной/resume/subagent) и кладёт в запрос; openai-compat и anthropic деградируют image-части user-сообщений и tool-результатов в один общий текстовый placeholder[Image attachment omitted: this model does not support image input](паттерн E8.3 #331).nil= прежнее поведение (aux-вызовы без медиа не затронуты). Обходной путь для существующих сломанных сессий: новая сессия чата (картинка в окне истории продолжала бы 400-ить и после фикса — теперь вместо 400 модель увидит placeholder).
Fixed (#406)
- Ошибка провайдера в чате — человекочитаемый текст вместо сырой строки SDK с килограммом JSON.
providers.HumanizeError(err) (userText, detail): словарь по статусам/типу (400/401/403/404/429/5xx/таймаут/DNS/подключение — обобщение словаря test-connectivity),detail— полный текст ошибки с капом 4000 байт, rune-safe обрезкой, нормализацией невалидного UTF-8 и редъакцией секретов (Bearer/api_key/sk-токены с якорями против ложных срабатываний —claude-sk-…и пути не трогаются); редъакция до капа в обеих ветках (userText-фолбэки и detail). Терминальные ветки актора (run_error, resume-final-error; TTFB-текст #400 сохранён приоритетнее словаря, для resume теперь тоже) шлют в чат короткий текст +_error_detailв метаданных; WS-событиеerrorнесётDetail; WebUI рендерит error-бабл (danger-акцент, ⚠️,role="status") со сворачиваемыми «Техническими деталями» (клиентский страховочный кап UTF-16, суррогатные пары не рвутся); флагиturn_failed/error_detailпереживают merge с серверной строкой (переносятся на строку-замену); email получает короткий текст. В БД персистится короткий текст (полный — в llm-логе).
Review (#405, #406)
- ocr review — 8 раундов; все high/medium исправлены: гейт tool-результатов в anthropic (image-блоки из enhanced-тузов шли мимо гейта), редъакция секретов (порядок редъакция→кап, прокси-сепараторы
Bearer=/Bearer:, якоря sk-токенов), байтовый инвариант капа («…» больше не превышает лимит), TTFB-паритет resume-ветки, дедуп error-баблов (#348-семантика сохранена), перенос клиентских флагов через mergeServerMessages, a11y (role="status"), имяturn_failedвместо коллизионногоis_error, rune-safe обрезка кириллицы. Осознанно оставлено: дублирование логики деградации image-части между провайдерами (3 маленьких сайта с разыми SDK-типами блоков), отсутствие юнит-теста клиентского страховочного капа (защитная сеть, серверный кап протестирован). Проверки:go test ./... -count=1(0 падений),golangci-lint(0 новых; 20 легаси-SA5011 в нетронутых тестах),go vet,npm run check(0),npm test(891),make build-cross(6 платформ) — зелёные. Диагноз подтверждён llm-логами прода (100.64.0.5) до начала фикса.