Перейти до основного вмісту

Керування сесіями та ущільнення (детальний розбір)

У цьому документі пояснюється, як OpenClaw керує сесіями наскрізно:
  • Маршрутизація сесій (як вхідні повідомлення зіставляються з sessionKey)
  • Сховище сесій (sessions.json) і що воно відстежує
  • Збереження транскриптів (*.jsonl) та їхня структура
  • Гігієна транскриптів (специфічні для провайдера виправлення перед запусками)
  • Обмеження контексту (вікно контексту проти відстежуваних токенів)
  • Ущільнення (ручне й автоущільнення) та куди підключати роботу перед ущільненням
  • Тихе обслуговування (наприклад, запис пам’яті, який не має створювати видимий користувачу вивід)
Якщо спочатку потрібен огляд на вищому рівні, почніть з:

Джерело істини: Gateway

OpenClaw спроєктований навколо єдиного процесу Gateway, який володіє станом сесій.
  • UI (додаток macOS, вебінтерфейс Control UI, TUI) мають опитувати Gateway щодо списків сесій і кількості токенів.
  • У віддаленому режимі файли сесій розміщені на віддаленому хості; «перевірка локальних файлів на вашому Mac» не відображатиме те, що використовує Gateway.

Два шари збереження

OpenClaw зберігає сесії у двох шарах:
  1. Сховище сесій (sessions.json)
    • Мапа ключ/значення: sessionKey -> SessionEntry
    • Невелике, змінюване, безпечне для редагування (або видалення записів)
    • Відстежує метадані сесії (поточний ідентифікатор сесії, останню активність, перемикачі, лічильники токенів тощо)
  2. Транскрипт (<sessionId>.jsonl)
    • Транскрипт лише з додаванням із деревоподібною структурою (записи мають id + parentId)
    • Зберігає фактичну розмову + виклики інструментів + підсумки ущільнення
    • Використовується для відновлення контексту моделі для майбутніх ходів

Розташування на диску

Для кожного агента, на хості Gateway:
  • Сховище: ~/.openclaw/agents/<agentId>/sessions/sessions.json
  • Транскрипти: ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
    • Сесії тем Telegram: .../<sessionId>-topic-<threadId>.jsonl
OpenClaw визначає ці шляхи через src/config/sessions.ts.

Обслуговування сховища та контроль диска

Збереження сесій має автоматичні механізми обслуговування (session.maintenance) для sessions.json і артефактів транскриптів:
  • mode: warn (типово) або enforce
  • pruneAfter: поріг віку застарілих записів для очищення (типово 30d)
  • maxEntries: обмеження кількості записів у sessions.json (типово 500)
  • rotateBytes: ротація sessions.json, якщо файл завеликий (типово 10mb)
  • resetArchiveRetention: строк зберігання для архівів транскриптів *.reset.<timestamp> (типово: такий самий, як pruneAfter; false вимикає очищення)
  • maxDiskBytes: необов’язковий бюджет каталогу сесій на диску
  • highWaterBytes: необов’язкова ціль після очищення (типово 80% від maxDiskBytes)
Порядок примусового очищення для бюджету диска (mode: "enforce"):
  1. Спочатку видалити найстаріші архівні або осиротілі артефакти транскриптів.
  2. Якщо все ще вище за ціль, витіснити найстаріші записи сесій і їхні файли транскриптів.
  3. Продовжувати, доки використання не стане меншим або рівним highWaterBytes.
У режимі mode: "warn" OpenClaw повідомляє про потенційні витіснення, але не змінює сховище/файли. Запустити обслуговування на вимогу:
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce

Cron-сесії та журнали запусків

Ізольовані запуски cron також створюють записи сесій/транскрипти, і для них є окремі налаштування зберігання:
  • cron.sessionRetention (типово 24h) очищає старі сесії ізольованих запусків cron зі сховища сесій (false вимикає).
  • cron.runLog.maxBytes + cron.runLog.keepLines очищають файли ~/.openclaw/cron/runs/<jobId>.jsonl (типові значення: 2_000_000 байтів і 2000 рядків).

Ключі сесій (sessionKey)

sessionKey визначає, у якому кошику розмови ви перебуваєте (маршрутизація + ізоляція). Поширені шаблони:
  • Основний/прямий чат (для кожного агента): agent:<agentId>:<mainKey> (типово main)
  • Група: agent:<agentId>:<channel>:group:<id>
  • Кімната/канал (Discord/Slack): agent:<agentId>:<channel>:channel:<id> або ...:room:<id>
  • Cron: cron:<job.id>
  • Webhook: hook:<uuid> (якщо не перевизначено)
Канонічні правила описані в /concepts/session.

Ідентифікатори сесій (sessionId)

Кожен sessionKey вказує на поточний sessionId (файл транскрипту, що продовжує розмову). Практичні правила:
  • Скидання (/new, /reset) створює новий sessionId для цього sessionKey.
  • Щоденне скидання (типово о 4:00 ранку за місцевим часом на хості gateway) створює новий sessionId під час наступного повідомлення після межі скидання.
  • Завершення через неактивність (session.reset.idleMinutes або застаріле session.idleMinutes) створює новий sessionId, коли повідомлення надходить після вікна неактивності. Коли налаштовано і щоденне скидання, і неактивність, спрацьовує те, що завершується першим.
  • Захист від розгалуження батьківського транскрипту (session.parentForkMaxTokens, типово 100000) пропускає розгалуження батьківського транскрипту, якщо батьківська сесія вже надто велика; новий потік починається з нуля. Установіть 0, щоб вимкнути.
Деталь реалізації: рішення ухвалюється в initSessionState() у src/auto-reply/reply/session.ts.

Схема сховища сесій (sessions.json)

Тип значення сховища — SessionEntry у src/config/sessions.ts. Основні поля (не вичерпно):
  • sessionId: поточний ідентифікатор транскрипту (ім’я файлу виводиться з нього, якщо не задано sessionFile)
  • updatedAt: позначка часу останньої активності
  • sessionFile: необов’язкове явне перевизначення шляху до транскрипту
  • chatType: direct | group | room (допомагає UI та політиці надсилання)
  • provider, subject, room, space, displayName: метадані для позначення груп/каналів
  • Перемикачі:
    • thinkingLevel, verboseLevel, reasoningLevel, elevatedLevel
    • sendPolicy (перевизначення для окремої сесії)
  • Вибір моделі:
    • providerOverride, modelOverride, authProfileOverride
  • Лічильники токенів (best-effort / залежать від провайдера):
    • inputTokens, outputTokens, totalTokens, contextTokens
  • compactionCount: як часто для цього ключа сесії завершувалося автоущільнення
  • memoryFlushAt: позначка часу останнього скидання пам’яті перед ущільненням
  • memoryFlushCompactionCount: лічильник ущільнень на момент останнього скидання
Сховище безпечно редагувати, але Gateway є авторитетним джерелом: він може перезаписувати або відновлювати записи під час виконання сесій.

Структура транскрипту (*.jsonl)

Транскриптами керує SessionManager з @mariozechner/pi-coding-agent. Файл має формат JSONL:
  • Перший рядок: заголовок сесії (type: "session", містить id, cwd, timestamp, необов’язковий parentSession)
  • Далі: записи сесії з id + parentId (дерево)
Помітні типи записів:
  • message: повідомлення user/assistant/toolResult
  • custom_message: повідомлення, вставлені розширенням, які потрапляють у контекст моделі (можуть бути приховані від UI)
  • custom: стан розширення, який не потрапляє у контекст моделі
  • compaction: збережений підсумок ущільнення з firstKeptEntryId і tokensBefore
  • branch_summary: збережений підсумок під час навігації гілкою дерева
OpenClaw навмисно не «виправляє» транскрипти; Gateway використовує SessionManager для їх читання/запису.

Вікна контексту проти відстежуваних токенів

Мають значення дві різні концепції:
  1. Вікно контексту моделі: жорстке обмеження для кожної моделі (токени, видимі моделі)
  2. Лічильники сховища сесій: ковзні статистики, записані в sessions.json (використовуються для /status і панелей)
Якщо ви налаштовуєте обмеження:
  • Вікно контексту надходить із каталогу моделей (і може бути перевизначене через конфігурацію).
  • contextTokens у сховищі — це оцінка/значення звітності під час виконання; не сприймайте його як сувору гарантію.
Докладніше див. /token-use.

Ущільнення: що це таке

Ущільнення підсумовує старішу розмову в збережений запис compaction у транскрипті та залишає недоторканими недавні повідомлення. Після ущільнення майбутні ходи бачать:
  • Підсумок ущільнення
  • Повідомлення після firstKeptEntryId
Ущільнення є постійним (на відміну від обрізання сесії). Див. /concepts/session-pruning.

Межі фрагментів ущільнення та парування інструментів

Коли OpenClaw розбиває довгий транскрипт на фрагменти для ущільнення, він зберігає парування між викликами інструментів асистента та відповідними записами toolResult.
  • Якщо поділ за часткою токенів припадає між викликом інструмента та його результатом, OpenClaw зсуває межу до повідомлення асистента з викликом інструмента, а не розділяє пару.
  • Якщо кінцевий блок результатів інструмента інакше виштовхнув би фрагмент за цільовий розмір, OpenClaw зберігає цей очікуваний блок інструмента й залишає неузагальнений хвіст недоторканим.
  • Перервані/помилкові блоки викликів інструментів не утримують очікуваний поділ відкритим.

Коли відбувається автоущільнення (Pi runtime)

У вбудованому агенті Pi автоущільнення запускається у двох випадках:
  1. Відновлення після переповнення: модель повертає помилку переповнення контексту (request_too_large, context length exceeded, input exceeds the maximum number of tokens, input token count exceeds the maximum number of input tokens, input is too long for the model, ollama error: context length exceeded та подібні варіанти у форматі провайдера) → ущільнити → повторити спробу.
  2. Порогове обслуговування: після успішного ходу, коли:
contextTokens > contextWindow - reserveTokens Де:
  • contextWindow — це вікно контексту моделі
  • reserveTokens — запас токенів, зарезервований для промптів + наступного виводу моделі
Це семантика runtime Pi (OpenClaw споживає ці події, але Pi вирішує, коли ущільнювати).

Налаштування ущільнення (reserveTokens, keepRecentTokens)

Налаштування ущільнення Pi містяться в параметрах Pi:
{
  compaction: {
    enabled: true,
    reserveTokens: 16384,
    keepRecentTokens: 20000,
  },
}
OpenClaw також примусово застосовує мінімальний поріг безпеки для вбудованих запусків:
  • Якщо compaction.reserveTokens < reserveTokensFloor, OpenClaw збільшує його.
  • Типовий мінімум — 20000 токенів.
  • Установіть agents.defaults.compaction.reserveTokensFloor: 0, щоб вимкнути цей мінімум.
  • Якщо значення вже вище, OpenClaw залишає його без змін.
Чому: щоб залишити достатній запас для багатокрокового «обслуговування» (як-от записів пам’яті) до того, як ущільнення стане неминучим. Реалізація: ensurePiCompactionReserveTokens() у src/agents/pi-settings.ts (викликається з src/agents/pi-embedded-runner.ts).

Підключувані провайдери ущільнення

Плагіни можуть реєструвати провайдера ущільнення через registerCompactionProvider() в API плагіна. Коли agents.defaults.compaction.provider встановлено на ідентифікатор зареєстрованого провайдера, розширення safeguard делегує узагальнення цьому провайдеру замість вбудованого конвеєра summarizeInStages.
  • provider: ідентифікатор зареєстрованого плагіна-провайдера ущільнення. Залиште незаповненим для типового LLM-узагальнення.
  • Встановлення provider примусово задає mode: "safeguard".
  • Провайдери отримують ті самі інструкції ущільнення та політику збереження ідентифікаторів, що й вбудований шлях.
  • Safeguard усе одно зберігає контекст недавніх ходів і розділених ходів у суфіксі після виводу провайдера.
  • Якщо провайдер зазнає помилки або повертає порожній результат, OpenClaw автоматично повертається до вбудованого LLM-узагальнення.
  • Сигнали abort/timeout перевикидаються далі (не ковтаються), щоб поважати скасування з боку викликача.
Джерело: src/plugins/compaction-provider.ts, src/agents/pi-hooks/compaction-safeguard.ts.

Видимі користувачу поверхні

Ви можете спостерігати ущільнення й стан сесії через:
  • /status (у будь-якій чат-сесії)
  • openclaw status (CLI)
  • openclaw sessions / sessions --json
  • Детальний режим: 🧹 Auto-compaction complete + лічильник ущільнень

Тихе обслуговування (NO_REPLY)

OpenClaw підтримує «тихі» ходи для фонових завдань, де користувач не повинен бачити проміжний вивід. Домовленість:
  • Асистент починає свій вивід із точного тихого токена NO_REPLY / no_reply, щоб позначити «не доставляти відповідь користувачу».
  • OpenClaw видаляє/пригнічує це на рівні доставки.
  • Пригнічення точного тихого токена нечутливе до регістру, тож NO_REPLY і no_reply обидва зараховуються, коли весь вміст є лише тихим токеном.
  • Це призначено лише для справді фонових/недоставлюваних ходів; це не скорочення для звичайних дієвих запитів користувача.
Починаючи з 2026.1.10, OpenClaw також пригнічує потокове передавання чернетки/набору, коли частковий фрагмент починається з NO_REPLY, щоб тихі операції не просочували частковий вивід посеред ходу.

Попереднє «скидання пам’яті» перед ущільненням (реалізовано)

Мета: перед тим, як відбудеться автоущільнення, виконати тихий агентний хід, який записує довготривалий стан на диск (наприклад, memory/YYYY-MM-DD.md у робочому просторі агента), щоб ущільнення не могло стерти критичний контекст. OpenClaw використовує підхід скидання до досягнення порогу:
  1. Відстежувати використання контексту сесії.
  2. Коли воно перетинає «м’який поріг» (нижче порога ущільнення Pi), виконати тиху інструкцію «записати пам’ять зараз» для агента.
  3. Використовувати точний тихий токен NO_REPLY / no_reply, щоб користувач нічого не бачив.
Конфігурація (agents.defaults.compaction.memoryFlush):
  • enabled (типово: true)
  • softThresholdTokens (типово: 4000)
  • prompt (повідомлення користувача для ходу скидання)
  • systemPrompt (додатковий системний промпт, доданий для ходу скидання)
Примітки:
  • Типовий prompt/system prompt містить підказку NO_REPLY для пригнічення доставки.
  • Скидання виконується один раз за цикл ущільнення (відстежується в sessions.json).
  • Скидання виконується лише для вбудованих сесій Pi (бекенди CLI його пропускають).
  • Скидання пропускається, якщо робочий простір сесії доступний лише для читання (workspaceAccess: "ro" або "none").
  • Див. Memory, щоб дізнатися про структуру файлів у робочому просторі та шаблони запису.
Pi також надає хук session_before_compact в API розширення, але логіка скидання в OpenClaw сьогодні живе на боці Gateway.

Контрольний список усунення несправностей

  • Неправильний ключ сесії? Почніть з /concepts/session і підтвердьте sessionKey у /status.
  • Невідповідність між сховищем і транскриптом? Підтвердьте хост Gateway і шлях до сховища з openclaw status.
  • Забагато ущільнень? Перевірте:
    • вікно контексту моделі (замале)
    • налаштування ущільнення (reserveTokens, завелике для вікна моделі, може спричиняти ранніше ущільнення)
    • роздування toolResult: увімкніть/налаштуйте обрізання сесії
  • Тихі ходи просочуються? Переконайтеся, що відповідь починається з NO_REPLY (точний токен, нечутливий до регістру) і що ви використовуєте збірку, яка містить виправлення пригнічення потокової передачі.