0.167.12
Fixed
- Живые
role=toolсообщения в БД: инструментальный контекст теперь переживает границу хода ( — P0/blocker; реализация ADR2026-08-20-live-tool-messages). Корневой дефект контекстного слоя: инструментальная работа агента не переживала границу хода. Внутри хода ReAct-цепочка вspec.Messagesбыла корректной, но в БД писалась под служебными ролямиtool_call_history(превью, обрезанные до 2000 байт) иtool_iteration; обе роли исключались изdialogRoleFilter, обратно не парсились нигде. Следствия: агент перечитывал файлы, перезапускал команды, повторял отклонённые подходы, Todo-лист был невидим (обещание системного промпта «You remember it through your previous todo_write calls» не выполнялось). Фикс: миграция 106tool_messages_is_error(оба каталога, SQLite+PG) — колонкаmessages.is_error BOOLEAN NOT NULL DEFAULT 0/FALSE+ индексidx_messages_agent_role_id(agent_id, role, id)+ANALYZE;ChatMessage.IsErrorв store-слое (все SELECT/INSERT/scan вsqlite.goиpostgres.go; дублированные списки колонок консолидированы в константыmsgCols/pgMsgCols);runner.goперсистит живую цепочку синхронно —assistantс заполненнойtool_calls(JSON) ДО выполнения инструментов иrole=toolна каждый результат сtool_call_id/tool_name/is_errorцеликом (доMaxToolResultChars; 2000-байтовые превью устранены); защита от персиста отменённого хода (ADR 2026-07-04/#254) сохранена в обеих точках, orphan-assistant при отмене вычищаетсяrepairToolPairsна чтении; записиtool_call_historyизrunner.goиstreamHook.AfterIterationудалены (tool_iteration— артефакт UI — не тронут); чтение — новыйbuildHistoryFromDB(actor.go) переноситis_errorи парситtool_calls, мёртвый skip-list удалён (роли уже фильтруются SQL);uiRoleFilter(оба стора) дополнительно скрывает промежуточныеassistantс пустым content и непустымиtool_calls— рендер чата в WebUI не меняется; дубль-персист ask_user assistant удалён (runner пишет сам;findPendingAskUserCoreустойчив к множественным tool_calls);tool_logпереписан на чтение живой цепочки (привязка результатов поToolCallIDк родительской записи) с сохранением legacy-режимаtool_call_history; провал инструмента (включая timeout, panic в parallel-батче, rate-limit, streaming-ошибку) помечаетсяIsError=trueи включается в результаты — assistant tool_call больше не остаётся без ответа (невалидная пара для LLM API) и LLM видит причину провала в текущем и следующем ходу. is_errorхранится в БД ( — P1, БД-часть; round-trip конвертеров — v0.167.10). Колонкаmessages.is_error(миграция 106) проходит полный цикл:runner.goпишет флаг с каждымrole=toolрезультатом,buildHistoryFromDBчитает вMessage.IsError— доезжает до Anthropictool_result.is_error/<tool_error>/ extra-поля openai_compat (конвертеры зафиксированы в v0.167.10). Тесты: round-trip через реальную SQLite-БД (TestAddMessage_IsErrorRoundTrip), персист сis_errorиз runner (TestRun_PersistsToolIsError), диалоговое окно возвращает флаг (TestGetRecentDialogMessages_ToolRoleAndIsError).- Токен-бюджет истории включён:
pruneHistoryByTokens+adjustCutForToolGroupsперестали быть мёртвым кодом ( — P1). Единственным ограничителем истории был счётчик сообщений: одно tool-сообщение на 40K токенов проходило без сопротивления, а рассчитанныйComputeBudget().Historyпопадал только в отладочный лог. После включения живыхrole=tool(см. выше) отсутствие жёсткого токен-гейта стало критичным. Фикс: новыйapplyHistoryBudget(context.go) вызывается в реальном путиhandleInbound— порядок уровней:verbatimCount-окно →FastTrimToolResults→applyHistoryBudget(жёсткий гейт поComputeBudget(contextMaxTokens).Historyс атомарностью tool-групп и защитой последнего user-сообщения) →repairToolPairs(вычищает разорванные пары на границе среза); на вырожденном входе (гигантский tool-хвост сам не влезает в бюджет) — обрезка хвоста до бюджета с повторным гейтом (copy-on-write, вход не мутируется), последнее user-сообщение не обрезается никогда; расхождение источников контекста устранено —ContextBuilder.ContextMaxTokensзаполняется изresolveContextMaxTokens(единая точка actor-слоя),agentBudgetиспользует его. Тесты:TestApplyHistoryBudget_TrimsToBudget(обрезка до бюджета + защита user),_SmallHistoryUntouched,_NoPanicOnDegenerateInput(бюджет ≤0, гигантское tool-сообщение),_ToolGroupsAtomic(нет orphantool_call_id).