# 10 — Обмен сообщениями

**Русский** · [English](../10-messaging.md)

Пиры обмениваются сообщениями по протоколу IAP. Агенты делают это инструментом `send_to_peer`, оператор — командой `iapeer send`. Оба пути ведут через один и тот же роутинг демона.

## Два способа отправить

**`send_to_peer`** — MCP-инструмент, который получает каждый агент claude/codex (через подключение к демону). Это основной канал между агентами.

```text
send_to_peer(personality="assistant", message="...", topic?, attachments?)
```

**`iapeer send`** — отправка из командной строки, тот же путь доставки в обход агентской сессии (работает, даже когда HTTP-слушатель демона недоступен):

```bash
iapeer send assistant --message "текст"
iapeer send assistant --message-file ./report.md       # тело из файла; '-' = stdin
iapeer send assistant --message "см. вложение" --attachment ./report.pdf
iapeer send assistant --message "..." --topic "релиз" --from claude-reviewer
```

Флаг `--from` задаёт отправителя (`<рантайм>-<имя>`); по умолчанию — идентичность пира текущей папки. `--attachment` повторяемый. `--message-file` с телом из файла или stdin удобен для длинных и многострочных сообщений.

## Владение вложениями

Аргумент вложения — **путь источника**, а не доставленный путь. До сборки конверта `routeSend` открывает каждый источник как обычный файл и копирует его байты в foundation-owned inbox целевого пира:

```text
~/.iapeer/state/iapeer/attachments/<получатель>/<sha256>/<имя-файла>
```

В конверт попадают абсолютные пути этих копий. Поэтому исход `ok`/`delivered`/`queued` одновременно значит, что каждое вложение уже имеет читаемую копию получателя; отправитель может сразу удалить или переименовать исходник. Отсутствующий, нечитаемый или необычный файл валит отправку до доставки. Пересылка inbox-файла третьему пиру создаёт отдельную копию в inbox третьего пира.

Копия — состояние получателя, а не кэш: по возрасту не удаляется и живёт столько же, сколько пир-получатель. `iapeer remove <получатель>` удаляет весь inbox. Удаление отправителя, очистка `/tmp`, рестарт демона, дренаж ephemeral-очереди и ротация истории моста её не удаляют.

## Путь доставки

Демон находит получателя в реестре и сначала выбирает поверхность доставки. Без явного `runtime` это всегда `default_runtime` адресата; живость других объявленных рантаймов выбор не меняет. Явный `runtime` выбирает ровно указанную поверхность. Затем демон смотрит на состояние выбранной поверхности:

- **живой** — демон пишет сообщение в сессию пира через сокет супервизора на ввод сессии. Демон ждёт подтверждения, что ввод принят (поле ввода очистилось); ответ — `доставлено`.
- **занят** (агент в середине хода, поле ввода не пустое) — сообщение встаёт в очередь композера и доставляется, как только агент освободится; ответ отправителю — `в очереди`. Очередь ждёт до 120 секунд, потом досылает принудительно.
- **спит** — демон поднимает сессию, перепроверяет получателя, доставляет; ответ — `доставлено, разбудил`.
- **остановлен** — демон отказывает и сообщает отправителю прямо.

Ключевая гарантия: `доставлено` означает, что сообщение действительно легло в живую сессию (демон дождался подтверждения), а не просто было отправлено в пустоту. Если сессия не подтвердила приём в отведённое время, демон считает её мёртвой и не лжёт об успехе.

В конверте каждого сообщения едет природа отправителя (`intelligence`) — получатель знает, пишет ему человек, агент или служебный процесс.

## Ограничения сообщения

У протокола есть пределы: тело сообщения — до 16000 символов, тема — до 200, вложений — до 20 за раз. Сообщение сверх лимита нужно разбивать или передавать содержимое файлом-вложением.

## Отправка в Telegram только со своим ботом

Пир не может слать сообщения в Telegram-домен, если у него нет привязанного Telegram-бота. Это защита: ответ человеку уходит через бота конкретного агента, и пир без такой привязки в Telegram не пишет — доставка ему отказывается. Привязка делается командой `iapeer connect telegram` (см. [09 — Рантаймы](09-рантаймы.md)).

## Контрольные команды

Контроль сессии идёт отдельным каналом от сообщений — это не текст в диалог, а управляющее воздействие:

```bash
iapeer interrupt assistant     # прервать текущий ход (Escape), контекст цел
iapeer compact assistant       # сжать диалог
```

`interrupt` останавливает зашедший не туда или зависший ход, не теряя контекст. `compact` сжимает диалог; если пир спит после чистого усыпления, демон сначала продолжит диалог, потом сожмёт, а для пустой сессии честно ответит, что сжимать нечего.

Отдельно стоят **алиасы** — шорткаты вида `/alias_new`, `/alias_compact`, заданные в профиле пира. Это не контроль, а заготовки текста: рантайм разворачивает алиас в полный текст и доставляет его пиру как обычное сообщение. Так оператор одной короткой командой запускает заранее прописанный сценарий (например, «сохрани состояние в память и перезапустись свежим»).

## Эфемерные воркеры

Пир с политикой пробуждения `wake_policy: "ephemeral"` в профиле работает иначе обычного агента — он предназначен для одноразовых задач:

- **всегда свежий.** Каждая задача поднимает свежую сессию, без продолжения прошлого диалога.
- **очередь по одной.** Задачи такому пиру не доставляются в живую сессию параллельно — они выстраиваются в durable-очередь (переживает перезапуск демона) и обрабатываются строго по одной. Демон докармливает очередь на надзорных тиках.
- **завершение после ответа.** Отправив свой единственный ответ, воркер помечается на тихое сворачивание: окно тишины (по умолчанию 20 секунд) — и демон закрывает сессию, никого не будя. Если воркер молчит и не отвечает, страховочный предел (по умолчанию 600 секунд) всё равно его свернёт.
- **`iapeer self-done`** — самовызов воркера, которому нечего отправить: освобождает очередь под следующую задачу, не разбудив никого. Доктрина «нечего отправлять — `self-done` вместо пустого ответа».

Эта модель держит поток одноразовых задач упорядоченным: один воркер на задачу, без накопления параллельных сессий, без пустых пробуждений адресата.

## Ответ человеку: origin guard

Ответ агента человеку обязан лечь в канал, из которого человек писал. Роутер закрепляет это механически: пока последнее сообщение человека этому агенту не отвечено, отправка в *другой* канал удерживается до подтверждения одной командой (`iapeer confirm-send <id>`) — вместо доставки. Ответы в тот же канал и инициатива проходят без трения. Полный контракт — модель взведённой пары, TTL, `confirm-send` — в [18 — Origin guard](18-origin-guard.md).
