fix(ai-chat): защита от петель агента — lockdown под тоггл, детектор деградации, бюджет шагов (#444)
Третий класс петли (инцидент 2026-07-10): ран упёрся в 20-шаговый кап, спалив все шаги на чтение; на 20-м шаге final-step lockdown отнял инструменты (toolChoice:'none') посреди незаконченной работы → модель выродилась в текст-повтор («loadTools.» ×20416, 255КБ). Пакет защит по дизайну владельца: - MAX_AGENT_STEPS 20→50; спеки выводятся из константы (нет захардкоженных 19/20). - Final-step lockdown под env-тогглом AI_CHAT_FINAL_STEP_LOCKDOWN (дефолт OFF, по образцу AI_CHAT_DEFERRED_TOOLS): OFF — инструменты доступны на всех шагах + мягкий финальный нудж; ON — легаси toolChoice:'none'+FINAL_STEP_INSTRUCTION. Спеки параметризованы по тогглу. .env.example задокументирован. - Пустой ход (все шаги без текста, шаги исчерпаны) получает синтетический маркер-текст — виден в UI и реплее. - Детектор токен-деградации в onChunk (единственная защита от болтовни, БЕЗ maxOutputTokens — tool-аргументы это выходные токены): чистые правила (≥25 одинаковых строк ИЛИ периодический хвост), при срабатывании abort через внутренний AbortController ∪ effectiveSignal (AbortSignal.any), финализация в onAbort: усечение хвоста, ai_chat_runs.error=Output degeneration detected, лизы MCP/снапшоты освобождаются (существующий lifecycle). - Предупреждение о бюджете шагов на MAX-6…MAX-2 с убывающим N. - loadTools-описание и преамбула каталога явно говорят, что CORE-тулы всегда активны (список из CORE_TOOL_KEYS динамически). Внутренний цикл: 2 прохода. Ревью нашло data-loss-риск: правило периодичности детектора ложно срабатывало на markdown-разделителях/setext-подчёркиваниях/ хвостовых пробелах (монохар-хвост p-периодичен при ЛЮБОМ p → ложный abort с пометкой error и усечением). Починка: отдельная монохар-проверка (порог 60, выше любого реального разделителя) + требование ≥2 различных символов в периодическом блоке при p≥2. Реальный loadTools-цикл (период ~10) ловится. Мутационно: 59 одинаковых — не флаг, 60 — флаг; loadTools×20416 — флаг. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -217,6 +217,17 @@ MCP_DOCMOST_PASSWORD=
|
||||
# active" behavior.
|
||||
# AI_CHAT_DEFERRED_TOOLS=true
|
||||
|
||||
# Final-step lockdown for the in-app agent loop (#444). Default OFF. When ON
|
||||
# (legacy), the LAST allowed step forces a text-only answer: the model's tools are
|
||||
# stripped (toolChoice=none) and a synthesis instruction is appended. That
|
||||
# tool-stripping caused a token-degeneration incident — robbed of its tools on the
|
||||
# final step mid-work, the model emitted a ~255KB block repeating a single token —
|
||||
# so the default is now OFF: the last step keeps its tools and gets only a SOFT
|
||||
# nudge to finish with a text summary, and a token-degeneration detector is the
|
||||
# universal anti-babble guard. Enable this ONLY for a model that reliably ends its
|
||||
# turns with a clear text answer.
|
||||
# AI_CHAT_FINAL_STEP_LOCKDOWN=false
|
||||
|
||||
# --- Autonomous / detached agent runs (settings.ai.autonomousRuns) ---
|
||||
# Opt-in per workspace (AI settings; off by default). When on, a chat turn becomes
|
||||
# a server-side RUN that survives a browser disconnect — only an explicit Stop ends
|
||||
|
||||
Reference in New Issue
Block a user