0.167.38

Added

  • Anti-loop: детекция повторных идентичных tool-вызовов внутри хода ( — P2). Раньше единственным ограничителем зацикливания модели был agent_max_iterations (при 0 — выключен вовсе): повторяя идентичный read_file/exec, модель сжигала токены и время до конца хода. Введён toolLoopDetector (internal/agent/loop_detector.go): подпись имя + канонический JSON аргументов (ключи map сортируются — разный порядок ключей даёт ту же подпись), счётчик серии ПОДРЯД идущих вызовов. На 3-м повторе инструмент не исполняется — модель получает [anti-loop]-предупреждение вместо результата (IsError=true, в метрики не попадает); на 5-м ход завершается StopReason="loop_detected" с внятным сообщением пользователю (actor.go, _loop_detected). Исключения: RepeatableTool (ask_user, tool_log, chat_history — повторы осмыслены) и аргумент-зависимый RepeatableCallChecker (self: check — поллинг, повторяем; set — детектируется, повторный идентичный set это как раз зацикливание). Параллельные батчи: loopStop-вердикт отменяет in-flight соседей (batchCancel) и прекращает исполнение следующих батчей; отмена контекста имеет приоритет над loop_detected (structural else-if); hook.AfterIteration — ровно один раз на итерацию с корректным StopReason. Документированные осознанные ограничения: порядок элементов массивов и числовое кодирование не канонизируются (сортировка массивов давала бы false positive на семантический порядок todo_write/exec); немаршалящиеся аргументы дают уникальные подписи (детекция для такого инструмента отключается — безопаснее ложного стопа). Метрика loops_detected (JSON snapshot + Prometheus taigaclaw_actor_loops_detected_total + карточка «Итерации» в UI). Тесты: warn на 3-м без исполнения, стоп на 5-м, разные аргументы ≠ повтор, интерливинг сбрасывает серию, repeatable/условная повторяемость, канонизация ключей, parallel-батч, конкурентные немаршалящиеся аргументы (race-safe nonce), реальные self/chat_history/ask_user/tool_log.
  • Интерфейс RepeatableTool/RepeatableCallChecker в internal/agent/tools/tool.go — контракт исключения инструмента из anti-loop учёта.

Fixed

  • Zero-value слоты parallel-batch больше не попадают в контекст. Guard tr.CallID == "" в цикле результатов (раньше — только на персисте): пустые role=tool раздули бы контекст следующего LLM-вызова. Найдено в ходе ocr review.