# Архитектура Chat Agent

Снимок исходников 04.11.2026. Желаемый production-состав определяется
[webrtc.drs](#archive-availability); revision, digest и health работающих задач проверяются отдельно.

## Компоненты и границы

| Компонент | Код | Назначение |
|---|---|---|
| Front / расширение Chrome | `src_front`, `extensions/chrome` | Чат, микрофон, Silero, Opus и исполнение `run_js` в документе |
| Gateway | `src_api_gateway` | Bootstrap браузера, NATS grants, прямой допуск команд в Agent, Monitor, архив/replay |
| Agent | `src_agent` | Pydantic tool loop, HTTP/SSE провайдер, общая очередь модели, отмена и owner fencing |
| Audio Ingress | `src_audio_ws_ingress` | Допуск, декодирование, архив, batch и единственный ASR listener |
| PostgreSQL | `src_postgres`, `src_shared` | Архив, журнал, receipts, каталог страницы и демонстрационные данные |

В DRS также присутствуют `chat_nats`, `audio_nats`, `nats_box`, `nats_ui`, `pgweb_mcp`:
всего 10 сервисов. Ruby/AsyncGraph и WebRTC ingress удалены из дерева.

## Основные передачи

- Браузер подключается через защищённый HTTPS bootstrap и NATS WebSocket.
  Команды `chat.ui.<client_id>.cmd.<command>` и `chat.audio.<client_id>.cmd.<command>`
  обрабатывает Gateway; права ограничены конкретным клиентом и профилем.
- Чат: Gateway → Agent (`chat.internal.agent.widget`).
  Agent вызывает адаптер провайдера в своём процессе и HTTP/SSE модели; события проходят через
  `nats.events.<user_id>` и Gateway в собственный канал клиента.
- Единственный инструмент страницы — `run_js({code})`. Код выполняется в Chrome
  USER_SCRIPT, `dom` обращается к документу; `pageTools` выбирает непустой нативный
  каталог либо текущий `window.webMcp`. [Контракт и ограничения](</experiments/voice-ai/archive/w/DOCS/RUN_JS.md>).
- Аудио: клиент → `chat.audio.<client_id>.pcm` → Audio Ingress.
  Протокол 4 передаёт Opus; клиент протокола 3 получает `audio_upgrade_required`. Границы Silero
  привязываются к отсчётам исходной записи. Ingress сам владеет тремя живыми
  потоками и одной диагностической резервацией; межсервисных lease/heartbeat нет.
- Ingress декодирует и подготавливает готовую фразу для ASR. Задание передаётся
  через `webrtc.komaroff.asr.stream.<session_id>` во внешний bridge/worker.
  Результат приходит в Audio Ingress через `webrtc.komaroff.asr.text.<session_id>`,
  проверяется один раз и передаётся через Gateway исходной панели. Только панель
  отправляет распознанный вопрос в Agent. NATS для чата и аудио разделены.

Внешний `py_faster_whisper` владеет ASR bridge, worker и file UI.
GPU/MIG/веса и шлюзы моделей находятся в связанном deployment-контуре; локальная
ссылка или зелёный CI не подтверждают их работоспособность.
Полный контракт, поля сообщений и совместимость — в [NATS](</experiments/voice-ai/archive/w/DOCS/NATS.md>),
разделах Monitor и Browser audio protocol 4. Исторические записи Core остаются
в журнале с прежним именем; отсутствующие стрелки не восстанавливаются предположениями.

## Хранение и диагностика

- `nats_log` — append-only наблюдения. `payload_ref` ссылается на сохранённое тело;
  журнал и схема используют одну проекцию, без дорисовывания отсутствующих передач.
- `audio_recordings/chunks/phrases/recording_events` — запись для распознавания,
  границы, настройки и подтверждения. В Opus-архиве нет второй постоянной PCM-копии.
- `widget_cache` хранит только каталог по `(session_id,context_id)`; неиспользуемый
  столбец `results` удаляется при инициализации без переноса старых результатов.
- Receipts и `chat_agent_owner` защищают от повторного выполнения и старого владельца.
  Заметки и aviation-таблицы имеют действующих потребителей; они не удаляются по имени.
- Полный [аудит таблиц и упрощений](</experiments/voice-ai/archive/w/DOCS/SIMPLIFICATION_2026-11-03.md>).

[Локальный запуск](</experiments/voice-ai/archive/w/DOCS/QUICKSTART.md>), [рабочие проверки](</experiments/voice-ai/archive/w/.knowledge/workflows.md>),
[поставка](</experiments/voice-ai/archive/w/DOCS/DEPLOYMENT.md>). Датированные C1–C4 и Trickle ICE сохраняют прежние измерения.

Gateway и Ingress владеют собственными lifecycle gates. При поставке закрываются
оба допуска, проверяются активные команды/аудио/replay и очереди Agent/LLM/ASR.
Допуск открывается в порядке Ingress → Gateway. Один экземпляр каждого владельца
и stop-first обязательны: горизонтальное масштабирование этим изменением не вводится.
