# Agent: очередь, история и отмена

Agent владеет попыткой пользовательского запроса. Core передаёт текст или ASR final,
Agent исполняет его через активный Ruby + AsyncGraph runtime и сохраняет итог в
PostgreSQL. Общий deadline 120 секунд включает очередь, инструменты и модель.

## Исполнение

Три обработчика и девять ожидающих запросов; максимум два ожидающих на сессию.
Внутри чата сохраняется порядок, независимые чаты выбираются справедливо.
LLM имеет собственный один активный слот, поэтому параллельность Agent не означает
три одновременные генерации внешней модели. Переполнение возвращает явный отказ.

`nats.agent.<user_id>` принимает запросы, `nats.agent.history.<user_id>` возвращает
историю и runtime context. Production runtime использует
`nats.workflow.run.ruby.node` / `nats.workflow.health.ruby.node`.
`chat.agent.requests` обслуживает status/cancel, `chat.agent.stream` — фрагменты.
Отмена отправляется в workflow, LLM и tools по отдельным control subjects.

Повтор session/request ID с тем же запросом возвращает существующий результат;
другой payload с тем же ID отклоняется. Поздние результаты отменённой попытки
игнорируются. Завершение и отмена согласуются одним переходом состояния: уже
сохранённый результат нельзя перезаписать отменой. Управляемые задачи и HTTP
соединения освобождаются; прекращение вычисления внешнего GPU не обещается.

## Данные и UI

Без изменения схемы используются `sessions`, `runtime_state`, `events`.
Optimistic conflict reruns укладываются в общий deadline и action budget.
Отменённый частичный ответ сохраняется в `events.meta` как incomplete draft и
исключается из успешного контекста. При отмене редактирования прежняя ветка
остаётся, отдельно сохраняется помеченный черновик. Успешное редактирование
перестраивает ветку от выбранного пользовательского turn.

Фрагменты UI ограничены интервалом 50 мс; snapshot активного запроса — раз в
секунду. Все request events имеют session/request/attempt/generation/sequence.
После reconnect клиент получает snapshot либо историю, полного replay Core NATS нет.
`user123` сохраняется; идентификатор диалога — отдельный UUID session.

## Проверка и исходники

[Контракты и реализация C1](</experiments/voice-ai/archive/w/DOCS/CHAT_AGENT_EXECUTION.md>),
[живые результаты C1](</experiments/voice-ai/archive/w/DOCS/CHAT_AGENT_EXECUTION_C1.md>),
[границы текущей поставки](</experiments/voice-ai/archive/w/DOCS/DEPLOYMENT.md>).

- [NATS service и state transitions](</experiments/voice-ai/archive/w/src_agent/service.py>)
- [request state](#archive-availability)
- [workflow и сохранение](#archive-availability)
- [DB helpers](</experiments/voice-ai/archive/w/src_agent/utils/db.py>)
- [runtime state](#archive-availability)

Запуск: `python -m src_agent.main` или `docker compose up -d src_agent` из `docker/`.
При `no responders` проверять именно configured Ruby node subject, без fallback
на альтернативный runtime. Production evidence требует точного image revision,
истории, отмены и независимых чатов, а не только HTTP 200.
