1.0.11
Fixed (#371)
- Терминальные error-тексты хода персистятся несогласованно (#371, найдено при аудите #369): таймаут хода писал
role='assistant'-строку с эхомmessage_persisted, а run error / no provider / отказ resume / resume run error — нет; в live клиент материализовал оптимистичный error-бабл, который до перезагрузки висел навсегда «неподтверждённым» (merge не находил серверную строку), а после F5 исчезал — расхождение live/reload. Продуктовое решение — паритет с таймаутом: всё, что показано в live, сохраняется в истории. Новый helperpersistAssistantTextWithEcho(bounded fresh-ctx 10с +addMessageWithRetry+ эхоassistantPersistedEchoMessageна WS-канале, best-effort: неудача записи логируется и не подавляет терминальное событие) подключён в пяти ветках: no provider («Ошибка: у агента не настроен LLM-провайдер…»), nil result («Агент не смог обработать запрос»), run error («Ошибка: …»), предраннеровский отказ resume («Не удалось возобновить ход») и resume run error;persistTurnTimeoutотрефакторен на тот же helper (поведение не изменилось). В resume-ветке с пустымFinalContentконтент синтезируется из ошибки («Ошибка: …», паритет с run_error-веткой основного хода) — раньше клиент получал пустой text и показывал безликое «Ошибка агента»; непустой частичный ответ показывается и персистится как есть. Фронтенд без изменений кода: свап id оптимистичного бабла по assistant-эху + rule-2 merge уже покрывают поток (добавлен TS-тест на error-лэйн). Осознанные trade-offs (из ocr review): паритет с reload — текстовый (wire-флаги_error/_turn_endвChatMessageне сохраняются: metadata-колонки нет,IsErrorзарезервирован заrole='tool'; после перезагрузки строка читается как обычный assistant-текст); персист синхронный — порядок «эхо раньше терминального события» это контракт #369/#371, на здоровой БД запись занимает миллисекунды; канал строки = канал терминального события (история агента не фильтруется по каналу:GetRecentUIMessages/GetRecentDialogMessagesвыбирают поagent_id, live-строки раннер вообще пишет без канала);err.Error()в тексте — не регрессия: тот же текст и раньше уходил пользователю в live-событии. Тесты: Go — helper (WS: строка+эхо с id строки; email: строка без эха), интеграционно no provider / run error / resume fail / resume run error (строка + эхо +_errorна терминале; синтез контента при пустом FinalContent), best-effort при полном отказе БД (терминальное событие публикуется, эха нет); TS — подтверждение error-бабла assistant-эхом по контенту.