Лимиты и усечения
Ядро обрезает на четырёх уровнях: ходы, контекст, вывод процесса, вложения. Ниже — что именно срабатывает, что видит модель и что делать, если упёрся.
Ходы
max_turns (дефолт 200, 0 — без лимита) — потолок ходов на один запуск цикла. Считаются все ходы, включая те, где модель только вызвала инструменты.
На последнем ходу цикл не падает: у модели запрашивается промежуточный итог, и запуск заканчивается с этим текстом. Лечится не поднятием лимита, а дроблением задачи: одна сессия — одна цель, дальше snens run --session <id> "продолжай".
Контекст
Что куда уходит: журнал сессии append-only и хранит всё, а провайдеру уезжает проекция. Уборка срабатывает, когда оценка проекции превышает бюджет.
| ключ | дефолт | смысл |
|---|---|---|
ctx_window | 1000000 | окно модели в токенах |
context_budget | 0 | порог уборки; 0 — авто: 100k при окне ≤300k, иначе 200k |
context_reserve | 8192 | запас до предела окна; для маленьких окон не больше ¼ окна |
context_target | 0 | цель после уборки; 0 — 70% бюджета |
keep_results | 5 | сколько последних результатов инструментов не трогать |
Бюджет всегда урезается физическим пределом: (ctx_window - reserve) * 85%. Профиль [models.<префикс>] перебивает автооценку для своей модели.
Уборка вырезает результаты инструментов от старых к новым, пока оценка не дойдёт до цели; на месте вырезанного остаётся заглушка с именем инструмента, размером, кодом возврата и хвостом команды. Последние keep_results результатов не трогаются — модель работает именно с ними. Уже вырезанное в кандидаты не попадает: повторного срабатывания нет.
Что делать: длинные исследования — в подагента (snens run --detach), их контекст отдельный; прочитанное не перечитывать (read --offset/--limit), а итог фиксировать в ctx commit; при упорном переполнении — поднять context_budget (цена: больше входных токенов на каждый ход) или явно ужать контекст.
Вывод процесса
| ключ | дефолт | что обрезает |
|---|---|---|
max_process_chars | 40000 | весь вывод одного вызова до отправки модели |
max_result_chars | 24000 | результат инструмента в проекции |
Два разных потолка: первый работает при запуске (что вообще попало в журнал), второй — в проекции (что из записанного доехало до модели). Второй ниже первого намеренно: в журнале полный вывод остаётся, в контекст едет хвост.
reduce_output = true (дефолт) сокращает вывод shell-команд до усечения: снимает ANSI, режет строки длиннее 400 символов с пометкой … (+N симв.), схлопывает повторы в [×N]. Инструменты реестра так не сокращаются — у них точный контракт (файл, JSON-событие), искажать повторы нельзя; но по max_process_chars усекаются и они.
Усечение симметричное: ¾ начала, [... обрезано N символов из M ...], ¼ конца. Обрезанное не теряется — полный вывод ложится в файл, модель получает путь в строке [полный вывод: …] и может дочитать. Бинарный вывод выносится в файл всегда.
Что делать: cat большого файла не нужен — read --offset/--limit, grep -n, потом точечное чтение; длинную команду дробить; нужен полный текст — просить его в файл и читать частями.
Таймауты
| ключ | дефолт | что обрывает |
|---|---|---|
timeout_seconds | 120 | один вызов run; у вызова есть свой timeout_seconds |
stream_idle_seconds | 120 | молчание стрима между кадрами — ход считается оборванным |
approval_timeout_seconds | 300 | ожидание одобрения привилегированного действия; 0 — очередь выключена |
Таймаут команды не выглядит падением: код возврата 124 и текст [таймаут Ns: команда прервана, вывод неполный…]. Лечится дроблением команды, своим timeout_seconds у вызова или уводом в фон.
stream_idle_seconds — защита от залипшего апстрима: соединение живо, данных нет. Ошибка называет, сколько секунд молчало и сколько символов успело прийти. Молчание дольше двух минут — это не «модель думает».
Вложения
| ключ | дефолт | что делает |
|---|---|---|
attachments | true | даёт инструментам канал вложений (SNENS_ATTACH_DIR) |
max_attachment_bytes | 33554432 (32 МБ) | потолок одного вложения |
Файл больше потолка не отправляется: в тексте результата появляется строка [вложение отброшено: N Б > потолка M Б — имя]. Нераспознанная как изображение картинка тоже не уходит — иначе модель получит 400 от провайдера. attachments = false убирает канал целиком: инструменты его не видят, провайдеру части не уходят.