---
read_when:
    - Потрібно, щоб агенти помічали, коли люди або інші агенти без їхнього відома змінюють сеанс
    - Ви налагоджуєте сповіщення про зміну стану, курсори спостереження або `session_status changesSince`
    - Вам потрібно зрозуміти, як батьківські агенти синхронізуються з дочірніми сеансами
sidebarTitle: Session state awareness
summary: 'Журнал сигналів постійного стану сеансу: версії стану, спостерігачі, сповіщення про застарілий стан і узгодження'
title: Обізнаність про стан сеансу
x-i18n:
    generated_at: "2026-07-16T17:55:36Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    prompt_version: 32
    provider: openai
    source_hash: bb4126a0802e1ca4418f225c792490493a78886089b81c3b4567f72090ce34f4
    source_path: concepts/session-state.md
    workflow: 16
---

Коли кілька сеансів працюють над однією проблемою — керівник делегує завдання дочірнім сеансам, людина безпосередньо переходить до робочого сеансу, два агенти координують дії через [`sessions_send`](/uk/concepts/session-tool) — кожен сеанс формує припущення про інші. Ці припущення застарівають щойно втручається інший учасник. Обізнаність про стан сеансу — це механізм, який виявляє втручання, одноразово сповіщає відповідний сеанс і дає йому простий спосіб синхронізуватися перед виконанням дій.

Разом працюють три складники:

1. **Стійкий журнал сигналів** записує вибрані зміни стану кожного сеансу.
2. **Спостерігачі** зберігають курсори для кожної цілі й отримують одне об’єднане сповіщення про застарілий стан.
3. **Узгодження** отримує точну різницю через `session_status` із `changesSince`.

## Журнал сигналів

OpenClaw додає типізовану подію до спільної бази даних стану (`session_state_events`), коли у відстежуваному сеансі відбувається суттєва зміна. Події містять метадані й однорядковий опис — але ніколи не вміст повідомлення.

| Тип                    | Коли записується                                         | Сповіщає спостерігачів |
| ---------------------- | -------------------------------------------------------- | ---------------------- |
| `human_direct_message` | Людина надсилає репліку безпосередньо у відстежуваний сеанс | Так                    |
| `upstream_missing`     | Зникає зовнішнє джерело приєднаного сеансу               | Так                    |
| `goal_changed`         | Стан цілі сеансу створено, оновлено або очищено          | Так                    |
| `child_spawned`        | Створено дочірній сеанс субагента або ACP                | Ні (ініціалізує курсор) |
| `run_completed`        | Дочірній запуск успішно завершується                     | Ні (лише журнал)       |
| `run_failed`           | Дочірній запуск завершується помилкою, перевищує час очікування або скасовується | Ні (лише журнал) |
| `compacted`            | Історію сеансу ущільнено                                 | Ні (лише журнал)       |
| `adopted`              | Сеанс із каталогу приєднано до OpenClaw                  | Ні (лише журнал)       |

Кожна подія вказує свого учасника (`human`, `agent` або `system`). Скасовані дочірні запуски й запуски з перевищеним часом очікування записуються як помилки, а точний результат (`cancelled`, `timeout` або `error`) зберігається в корисному навантаженні події.

**Версія стану** сеансу — це просто найбільший порядковий номер у його журналі, який відстежується у стійкому заголовку кожного сеансу й зберігається після очищення. Рядки `sessions_list` містять `stateVersion`, якщо в журналі сеансу є зміни; `session_status` завжди повідомляє його.

Типи, призначені лише для журналу, існують для історії узгодження, а не для сповіщень: звичайне доставлення відомостей про завершення дочірнього запуску залишається відповідальністю [оголошень субагентів](/uk/tools/subagents), і журнал сигналів ніколи його не дублює.

## Спостерігачі

Спостерігач — це сеанс, який зберігає курсор (`session_watch_cursors`) для цілі. Курсори створюються двома способами:

- **Неявно (зв’язки породження).** Коли сеанс породжує субагента або дочірній сеанс ACP, курсор батьківського сеансу автоматично ініціалізується версією породження дочірнього сеансу. Батьківські сеанси ніколи не підписуються вручну.
- **Явно (`sessions_send watch: true`).** Будь-який координатор може відстежувати ціль, яку він не породив: передайте `watch: true` у `sessions_send`, і після успішного надсилання відправника буде зареєстровано як спостерігача за сеансом, який фактично отримав повідомлення. Реєстрація починається з поточної версії стану цілі — попередня історія ніколи не створює сповіщень. Результат інструмента містить `watched: true|false`, якщо параметр було задано.

Ідентифікатор спостерігача має бути ключем сеансу з указаним агентом. У межах `session.scope="global"` спільний ключ `global` неоднозначний для різних агентів, тому такі сеанси отримують стійкий журнал і `changesSince`, але не проактивні сповіщення.

Відстеження очищується автоматично: термін дії рядків курсорів завершується разом із терміном зберігання журналу сигналів, вони видаляються після скидання сеансу-спостерігача та разом із будь-яким із двох сеансів. У v1 немає команди припинення відстеження.

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

Якщо зовнішнє джерело приєднаного сеансу видалено ззовні, три послідовні невдалі перевірки (приблизно три такти моніторингу) створюють один сигнал `upstream_missing` для його спостерігачів і видаляють зв’язок із зовнішнім джерелом. Подальше продовження сеансу з каталогу створює новий зв’язок.

## Сповіщення: одне, а не багато

Коли надходить подія, що передбачає сповіщення, а курсор спостерігача відстає, спостерігач отримує одне системне сповіщення під час своєї наступної репліки:

```
Сеанс "agent:main:subagent:child" змінено (іншим учасником). Узгодьте стан перед виконанням дій: session_status sessionKey "agent:main:subagent:child" changesSince 12.
```

Спостерігачі головного сеансу також негайно активуються через Heartbeat; вкладені спостерігачі-субагенти отримують сповіщення під час своєї наступної репліки.

Протокол навмисно запобігає надмірній кількості сповіщень:

- **Одне сповіщення в очікуванні для кожної пари спостерігач/ціль.** Текст сповіщення залишається побайтово незмінним, поки воно очікує, а черга системних подій усуває його дублікати, тому двадцять швидких змін однієї цілі все одно створюють лише один рядок у запиті спостерігача.
- **Зафіксована позначка.** Курсор фіксує свою сповіщену позицію, коли сповіщення додається до черги. Подальші суттєві події переміщують лише позначку суттєвих змін і не створюють повторного сповіщення.
- **Підтвердження під час вилучення з черги, повторне відкриття лише для проміжних змін.** Коли репліка спостерігача отримує сповіщення, курсор просувається. Якщо між додаванням до черги й вилученням із неї надійшли додаткові суттєві події, для решти відкривається рівно одне нове сповіщення.
- **Приглушення власних подій.** Спостерігач ніколи не отримує сповіщень про події, які спричинив сам.
- **Відновлення після перезапуску.** Сповіщення в очікуванні зберігаються в черзі в пам’яті; початкове сканування повторно створює їх зі стійких курсорів після перезапуску Gateway.

## Узгодження

Сповіщення точно вказує спостерігачу, що потрібно зробити. `session_status` із `changesSince: <version>` повертає типізовані події після цієї версії (до 200), не просуваючи жодного курсора:

```json
{
  "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 охоплюють власників ущільнення вбудованого середовища виконання; ущільнення, яке виконується лише нативним каркасом, реєструється не повністю.
- Докладні дані про результат скасування наразі створюють дочірні запуски ACP; скасування нативних субагентів відображаються як загальні помилки.
- Виявлення власного відлуння із зовнішнього джерела порівнює нормалізований текст користувача. Зовнішній запит, що збігається з одним із 10 останніх повідомлень користувача на стороні OpenClaw у цьому сеансі, вважається власним відлунням.
- Один локальний рядок Claude JSONL, більший за ліміт сканування 1 MiB за один цикл, блокує курсор цього сеансу у v1; некласифіковані байти ніколи не пропускаються.
- Перевірки Claude на спареному вузлі класифікують останні 50 елементів стенограми за один цикл. Більші сплески можуть опинитися поза межами вікна сканування v1.
- Читання історії Claude на спареному вузлі не надає однозначного результату про відсутність гілки, тому віддалені видалення Claude не класифікуються як `upstream_missing` у v1.
- Сеанси каталогу, які не було приєднано, залишаються поза рівнем обізнаності у v1.
- Сеанси, приєднані до появи цієї функції, не мають зв’язку із зовнішнім джерелом; один раз продовжте їх із каталогу, щоб розпочати моніторинг зовнішнього джерела.
- Зв’язки із зовнішніми джерелами передбачають, що кожен ключ приєднаного сеансу відповідає одному агенту-власнику (під час приєднання використовується агент сховища за замовчуванням). Приєднання однієї зовнішньої гілки кількома агентами у v1 не відстежується.

## Пов’язані матеріали

- [Інструменти сеансів](/uk/concepts/session-tool) — `sessions_send`, `session_status`, `sessions_list`
- [Субагенти](/uk/tools/subagents) — зв’язки породження й оголошення про завершення
- [Heartbeat](/uk/gateway/heartbeat) — як сповіщення в черзі активують головні сеанси
- [Керування сеансами](/uk/concepts/session) — ключі, області дії та життєвий цикл сеансів
