Sessions and memory
Осведомлённость о состоянии сеанса
Когда несколько сеансов работают над одной задачей — менеджер делегирует её дочерним сеансам, человек напрямую подключается к рабочему сеансу, два агента координируют действия через sessions_send — каждый сеанс формирует предположения о других. Эти предположения устаревают, как только вмешивается другой участник. Осведомлённость о состоянии сеанса — это механизм, который обнаруживает вмешательство, однократно уведомляет затронутый сеанс и предоставляет ему простой способ получить актуальные сведения перед выполнением действий.
Совместно работают три компонента:
- Устойчивый журнал сигналов регистрирует выбранные изменения состояния для каждого сеанса.
- Наблюдатели хранят курсоры для каждой цели и получают одно объединённое уведомление об устаревшем состоянии.
- Синхронизация получает точную дельту через
session_statusсchangesSince.
Журнал сигналов
OpenClaw добавляет типизированное событие в общую базу данных состояния (session_state_events), когда отслеживаемый сеанс существенно изменяется. События содержат метаданные и однострочную сводку, но никогда не содержат текст сообщений.
| Тип | Когда регистрируется | Уведомляет наблюдателей |
|---|---|---|
human_direct_message |
Человек отправляет реплику непосредственно в отслеживаемый сеанс | Да |
goal_changed |
Целевое состояние сеанса создаётся, обновляется или очищается | Да |
child_spawned |
Создаётся дочерний сеанс субагента или ACP | Нет (инициализирует курсор) |
run_completed |
Дочерний запуск успешно завершается | Нет (только журнал) |
run_failed |
Дочерний запуск завершается с ошибкой, превышает время ожидания или отменяется | Нет (только журнал) |
compacted |
История сеанса подвергается Compaction | Нет (только журнал) |
В каждом событии указан его инициатор (human, agent или system). Отменённые дочерние запуски и запуски с превышением времени ожидания регистрируются как ошибки, причём точный результат (cancelled, timeout или error) сохраняется в полезной нагрузке события.
Версия состояния сеанса — это просто наибольший порядковый номер в его журнале, отслеживаемый в устойчивой записи текущего состояния каждого сеанса, которая сохраняется после очистки. Строки sessions_list содержат stateVersion, если в журнале сеанса есть изменения; session_status всегда сообщает это значение.
Типы, предназначенные только для журнала, существуют для истории синхронизации, а не для уведомлений: обычная доставка уведомлений о завершении дочерних запусков остаётся в ведении уведомлений субагентов, и журнал сигналов никогда её не дублирует.
Наблюдатели
Наблюдатель — это сеанс, который хранит курсор (session_watch_cursors) для целевого сеанса. Курсоры создаются двумя способами:
- Неявно (связи создания). Когда сеанс создаёт дочерний сеанс субагента или ACP, курсор родительского сеанса автоматически инициализируется версией создания дочернего сеанса. Родительские сеансы никогда не оформляют подписку вручную.
- Явно (
sessions_send watch: true). Любой координатор может наблюдать за целью, созданной не им: передайтеwatch: trueвsessions_send, и после успешной отправки отправитель будет зарегистрирован как наблюдатель сеанса, фактически получившего сообщение. Регистрация начинается с текущей версии состояния цели — предыдущая история никогда не создаёт уведомлений. Результат инструмента сообщаетwatched: true|false, если параметр был задан.
Идентификатор наблюдателя должен быть ключом сеанса с указанием агента. В режиме session.scope="global" общий ключ global неоднозначен для разных агентов, поэтому такие сеансы получают устойчивый журнал и changesSince, но не получают проактивных уведомлений.
Наблюдения очищаются автоматически: срок действия строк курсоров истекает вместе со сроком хранения журнала сигналов, они удаляются при сбросе сеанса наблюдателя и при удалении любого из двух сеансов. В версии v1 команды прекращения наблюдения нет.
Уведомления: одно, а не множество
Когда регистрируется событие, предусматривающее уведомление, а курсор наблюдателя отстаёт, на следующем ходу наблюдатель получает одно системное уведомление:
Сеанс "agent:main:subagent:child" изменён (другим участником). Выполните синхронизацию перед действием: session_status sessionKey "agent:main:subagent:child" changesSince 12.Наблюдатели основных сеансов также немедленно пробуждаются через Heartbeat; вложенные наблюдатели-субагенты получают уведомление на следующем ходу.
Протокол специально предотвращает поток повторяющихся уведомлений:
- Одно ожидающее уведомление для каждой пары «наблюдатель/цель». Текст ожидающего уведомления остаётся побайтово неизменным, а очередь системных событий устраняет его дубликаты, поэтому даже двадцать быстрых изменений одной цели создают только одну строку в запросе наблюдателя.
- Зафиксированная контрольная отметка. При постановке уведомления в очередь курсор фиксирует позицию, о которой было отправлено уведомление. Дальнейшие существенные события изменяют только контрольную отметку существенных изменений; повторные уведомления не отправляются.
- Подтверждение при извлечении и повторное открытие только при чередующихся изменениях. Когда ход наблюдателя потребляет уведомление, курсор перемещается вперёд. Если между постановкой в очередь и извлечением появились дополнительные существенные события, для остатка создаётся ровно одно новое уведомление.
- Подавление собственных событий. Наблюдатель никогда не получает уведомления о событиях, которые вызвал сам.
- Восстановление после перезапуска. Ожидающие уведомления находятся в очереди в памяти; при запуске выполняется проход, который повторно формирует их из устойчивых курсоров после перезапуска Gateway.
Синхронизация
Уведомление точно указывает наблюдателю, что нужно сделать. session_status с changesSince: <version> возвращает типизированные события после указанной версии (не более 200), не перемещая курсоры:
{ "stateVersion": 19, "stateChanges": { "events": [ { "sequence": 14, "kind": "human_direct_message", "actorType": "human", "summary": "сообщение человека через telegram" }, { "sequence": 19, "kind": "goal_changed", "actorType": "human", "summary": "цель обновлена" } ], "historyGap": false }}historyGap: true означает, что запрошенная версия предшествует сохранённой истории — вместо интерпретации ответа как точной дельты обновите всё состояние сеанса (sessions_history, session_status). Сигнал о пробеле точен: он поступает из контрольной отметки очистки для конкретного сеанса, а не выводится из арифметики порядковых номеров.
Хранение и ограничения
История хранится в общей базе данных состояния и ограничена 30 днями и 50 000 строками; записи текущего состояния каждого сеанса остаются монотонными после очистки. Запись выполняется по возможности: ошибка добавления регистрируется в журнале и никогда не приводит к сбою исходного хода, поэтому stateVersion — это позиция в журнале сигналов, а не транзакционная версия отслеживания изменений данных.
Текущие ограничения:
- Доставка уведомлений предполагает, что общей базой данных состояния управляет один процесс Gateway. Несколько процессов Gateway совместно используют устойчивый журнал и
changesSince, но v1 не передаёт уведомления между процессами. - События Compaction охватывают владельцев Compaction во встроенной среде выполнения; Compaction, выполняемая только нативной инфраструктурой, регистрируется не полностью.
- Подробные данные о результате отмены в полезной нагрузке сейчас создаются дочерними запусками ACP; отмены нативных субагентов отображаются как общие ошибки.
Связанные разделы
- Инструменты сеансов —
sessions_send,session_status,sessions_list - Субагенты — связи создания и уведомления о завершении
- Heartbeat — как уведомления в очереди пробуждают основные сеансы
- Управление сеансами — ключи, области действия и жизненный цикл сеансов