0.164.0
Added
Синхронный
/stop: UI получает реальный статус остановки хода (ADR 2026-07-04, ). Раньше/stopбыл асинхронным:loop.goзвалcancel(), сразу публиковал_turn_end: trueи UI сбрасывал «thinking»-индикатор. Если cancel не пробивал блокирующую операцию (зависший LLM/exec/MCP) — пользователь думал, что ход остановлен, но тот продолжался и расходовал токены. В проде зафиксировано 5 подряд/stop(04-07-2026, агентsemen), каждый разinterrupted-divider записывался в БД, но ход не отменялся.Новый протокол (
internal/agent/loop.go:handleStop) —cancel()→WaitForIdle(новый метод наSessionActor, ждёт выходаhandleInboundчерез pollingbusyфлага) → cleanup очередей → записьinterrupted-divider → публикация_turn_endс реальным статусомstopped/still_running/already_idle. Порядок критичен: divider обязан оказаться в БД раньше, чем UI получит_turn_end.UI (
web/src/lib/stores/chat.svelte.ts) — больше НЕ сбрасываетwaitingForAgentмгновенно при отправке/stop; ждёт_turn_endот сервера.Setting
stop_wait_timeout_seconds(1–30 сек, по умолчанию 5) — таймаут ожидания; по истечении UI видит «Не удалось остановить ход за 5s…».Тесты —
TestWaitForIdle_*(3 сценария),TestHandleStop_WaitsAndWritesDivider,TestHandleStop_AlreadyIdleStatus.ocr review20 замечаний, валидные устранены (см. ниже).Setting
stop_wait_timeout_seconds(1–30 сек, по умолчанию 5) — таймаут ожидания для синхронного/stop.
Changed
Терминальность финального ответа:
hasContinuationMarkerи continuation-loop удалены (ADR 2026-07-04, ). Раньше приStopReason="stop"+ эвристике «сделаю / let me / i’ll» в финальном ответе запускалось до 3 доп. итераций ([System] Продолжай выполнение задачи.). False positive на «I’ll think about it» продлевал ход после финала. Теперь финал строго терминален: если LLM обрезан, пользователь явно скажет «продолжай», либо LLM используетask_user. УдаленыcontinuationMarkers,loadMaxContinuation, settingagent_max_continuations(from ParamRegistry иdocs/guide/configuration.md). ADR 2026-05-05 помечен как «частично отменён».Subagent injection на финальном ответе:
continue→return(ADR 2026-07-04, ). Вinternal/agent/runner.goприStopReason="stop"InjectionCallbackбольше НЕ вызывается. Subagent-результат остаётся вpendingInjectionsactor’а и попадёт в контекст следующего хода. Это устраняет риск, что orphan-subagent (переживший cancel) продлит отменённый ход.
Fixed
persistTurnTimeout: recover + retry + логирование (ADR 2026-07-04, ). При расследовании эпизода 04-07-2026 обнаружено:persistTurnTimeoutне сработал в 10:09 приagent_turn_timeout_minutes=60— нет ни WARN-лога «agent turn timed out», ни assistant-сообщения, ниwip_turnв scratchpad. Фикс:Тело обёрнуто в
defer recover()— паника в defer больше не молча убивает функцию.AddMessageретраится 1 раз через 200мс на transient-ошибку БД (addMessageWithRetry).Логирование ошибок записи divider’а и cleanup очереди в
handleStop(раньше silently проглатывались).Тесты —
TestPersistTurnTimeout_RecoversFromPanic(сpanickingStoreзаглушкой).ctx-аудит: операции, переживающие
ctx.Done()хода (ADR 2026-07-04, ). Несколько мест в коде выполняли async-persist отвязанно от ctx хода и могли пережить interrupt:internal/agent/runner.go:236—AsyncAddMessage(context.Background(), …)дляtool_call_history: теперь пропускается, еслиctx.Err() != nil(с INFO-логом). Регрессионные тестыTestRun_CancelledCtxSkipsToolCallHistoryPersist+TestRun_NormalCtxPersistsToolCallHistory.internal/agent/runner.go— добавлен early-return поctx.Err() != nilпосле tool execution (защита от 5-мин блокировки наInjectionCallback→pendingCond.Wait).internal/agent/actor.go:1184-1196— горутиныbgWG(autoCompact,pruneToolResults): WARN-лог только приerrors.Is(ctx.Err(), context.Canceled)(раньше ловил и нормальныйDeadlineExceeded, засоряя логи).PG-миграция
kg_extraction_queue. На проде192.168.2.104(PostgreSQL) постоянный WARNотношение "kg_extraction_queue" не существует (SQLSTATE 42P01)— миграция045_kg_queueне была применена (инстанс инициализирован до её создания). Добавлена idempotent-миграция104_kg_queue_ensure.up.sql(SQLite + PG, парные down) —CREATE TABLE IF NOT EXISTS+INSERT … ON CONFLICT DO NOTHINGбэкфилл.
ADR
- ADR 2026-07-04 «Терминальность прерывания и финального ответа агента» — формализация инварианта «прерывание и финальный ответ — терминальные состояния». Описывает 7 изменений (P0-1 … P2-8), из которых 6 реализованы в этом релизе, 2 (P1-6, P2-7) закрыты как already-covered существующими механизмами.
Issues
- #252 [P0-1] Синхронный /stop — fixed
- #253 [P0-2] persistTurnTimeout recover/retry — fixed
- #254 [P0-3] ctx-аудит — fixed
- #255 [P1-4] Удалить hasContinuationMarker — fixed
- #256 [P1-5] runner continue→return — fixed
- #257 [P1-6] cleanupSubagents — closed (duplicate, уже реализовано в b8a1e76)
- #258 [P2-7] Skip abandoned tool_call_history — closed (covered by P0-3 + существующий фильтр)
- #259 [P2-8] PG-миграция kg_queue ensure — fixed