# 5 - Assistant Mode Architecture Report (2026-03-24)

## 1. Статус этапа

Дата фиксации: **24 марта 2026**.

На текущем этапе реализован рабочий `Assistant Mode` поверх существующего `Decomposition` контура:

- decomposition/debug режим сохранен и не удален;
- добавлен отдельный backend endpoint для assistant-loop;
- добавлен слой `answer_composer` (human-readable ответ);
- добавлена session-scoped история диалога (in-memory);
- добавлен debug drawer в GUI по каждому assistant ответу;
- единый pipeline нормализации/маршрутизации используется для обоих режимов.

---

## 2. Что входит в текущую архитектуру

## 2.1 Backend

Ключевые узлы:

- `llm_normalizer/backend/src/routes/assistant.ts`
- `llm_normalizer/backend/src/services/assistantService.ts`
- `llm_normalizer/backend/src/services/answerComposer.ts`
- `llm_normalizer/backend/src/services/assistantSessionStore.ts`
- `llm_normalizer/backend/src/types/assistant.ts`
- `llm_normalizer/backend/src/services/routeHintAdapter.ts` (общий deterministic routing)
- `llm_normalizer/backend/src/services/normalizerService.ts` (общий normalizer pipeline)

Подключение в сервер:

- `llm_normalizer/backend/src/server.ts`
- `llm_normalizer/backend/src/serverContext.ts`

## 2.2 Frontend

Ключевые узлы:

- `llm_normalizer/frontend/src/App.tsx` (mode switch + orchestration)
- `llm_normalizer/frontend/src/components/AssistantPanel.tsx`
- `llm_normalizer/frontend/src/api/client.ts` (assistant API methods)
- `llm_normalizer/frontend/src/state/types.ts` (assistant типы состояния)
- `llm_normalizer/frontend/src/styles.css` (assistant/mode switch UI стиль)

---

## 3. Backend: функциональная архитектура

## 3.1 Endpoint’ы

### 3.1.1 POST `/api/assistant/message`

Назначение:

- принять user message;
- прогнать через normalizer pipeline;
- определить route/fallback;
- собрать human-readable assistant reply;
- вернуть reply + debug + session conversation snapshot.

Проверки:

- `user_message` обязателен;
- при пустом сообщении возвращается `INVALID_ASSISTANT_MESSAGE` (HTTP 400).

### 3.1.2 GET `/api/assistant/session/:session_id`

Назначение:

- вернуть текущую историю сессии из in-memory store.

Поведение:

- если сессия отсутствует: `ASSISTANT_SESSION_NOT_FOUND` (HTTP 404).

---

## 3.2 Контракт данных Assistant Mode

Типы заданы в:

- `llm_normalizer/backend/src/types/assistant.ts`

Ключевые сущности:

- `AssistantMessageRequestPayload`
- `AssistantDebugPayload`
- `AssistantConversationItem`
- `AssistantMessageResponsePayload`

`fallback_type` (жестко зафиксированный набор):

- `none`
- `out_of_scope`
- `clarification`
- `partial`
- `unknown`

---

## 3.3 Session memory

Реализовано в:

- `llm_normalizer/backend/src/services/assistantSessionStore.ts`

Характеристики:

- хранилище: in-memory `Map<session_id, session_state>`;
- auto-create сессии при первом сообщении;
- ограничение длины: `MAX_ITEMS_PER_SESSION = 200`;
- хранение только в рамках текущего backend процесса;
- при рестарте backend память очищается.

Это deliberate решение текущего этапа (sandbox/stage), без persistent storage.

---

## 3.4 Assistant pipeline (внутренний flow)

Реализовано в:

- `llm_normalizer/backend/src/services/assistantService.ts`

Порядок выполнения:

1. `ensureSession` -> получаем/создаем `session_id`.
2. Сохраняем user message как conversation item (`role=user`).
3. Формируем `NormalizeRequestPayload` с:
   - `promptVersion` по умолчанию `normalizer_v2_0_2`,
   - connection/prompt/context/useMock из запроса.
4. Вызываем `normalizerService.normalize(...)`.
5. По `route_hint_summary` строим retrieval plan (`buildRetrievalPlan`).
6. Передаем данные в `composeAssistantAnswer(...)`.
7. Формируем `debug` payload:
   - `trace_id`,
   - `route_summary`,
   - `fragments`,
   - `retrieval`,
   - `normalized`.
8. Сохраняем assistant message как conversation item (`role=assistant`).
9. Логируем structured event `assistant_message_processed`.
10. Возвращаем:
   - `assistant_reply`,
   - `conversation_item`,
   - `debug`,
   - `conversation`.

---

## 3.5 Routing rules (общий deterministic v2 engine)

Основные правила маршрутизации берутся из:

- `llm_normalizer/backend/src/services/routeHintAdapter.ts`

Правила выбора маршрута:

1. `live_mcp_drilldown`
   - если `asks_for_exact_object_trace = true`.
2. `batch_refresh_then_store`
   - если `asks_for_ranking_or_top = true` **или** `asks_for_period_summary = true`.
3. `hybrid_store_plus_live`
   - если `has_multi_entity_scope = true` и `asks_for_chain_explanation = true`.
4. `store_feature_risk`
   - если `asks_for_rule_check = true` и не chain;
   - также anomaly path: `asks_for_anomaly_scan = true` без ranking и без multi-entity chain.
5. `store_canonical`
   - default routed путь для in-scope, если нет более сильного сигнала.
6. `no_route`
   - если fragment out-of-scope / insufficient specificity / missing mapping / unsupported fragment type.

Fallback type в summary:

- `out_of_scope` — сообщение вне контура;
- `clarification` — нет routable in-scope fragment’ов из-за недоспецификации;
- `partial` — часть in-scope/routed, часть no-route/out-of-scope;
- `none` — все ок для текущего контура.

---

## 3.6 Answer composer rules

Реализовано в:

- `llm_normalizer/backend/src/services/answerComposer.ts`

Логика:

1. `out_of_scope`
   - вежливый boundary response (работа только по company-specific accounting contour).
2. `clarification`
   - конкретный уточняющий ответ: период/счет/документ/контрагент.
3. `partial`
   - сообщает, что обработана только часть запроса;
   - выводит routed части;
   - явно фиксирует sandbox retrieval mode.
4. `none`
   - human-readable summary с перечислением planned routes.
5. `unknown`
   - защитный fallback, если routed items не сформированы.

Важно:

- на этом этапе composer формирует **человеко-читаемый operational ответ**;
- это не финальный production-grade semantic answer over full live retrieval.

---

## 3.7 Retrieval слой (текущий статус)

Текущее состояние: **stubbed / sandbox retrieval plan**.

Что есть:

- генерация плана “что и по какому route исполнять”;
- диагностический payload по fragment’ам.

Чего пока нет:

- боевой deep retrieval из 1С по всем route;
- гарантированного factual grounding для каждого ответа assistant mode.

---

## 3.8 Логирование и трассировка

В `assistantService` пишется structured log c событием:

- `assistant_message_processed`

Поля:

- `session_id`
- `message_id`
- `user_message`
- `normalizer_output`
- `resolved_execution_state`
- `routes`
- `fallback_type`
- `retrieval_payloads`
- `assistant_reply`
- `trace_id`

Это дает базу для будущего field-eval hardening.

---

## 4. Frontend: функциональная архитектура

## 4.1 Режимы UI

Реализовано в:

- `llm_normalizer/frontend/src/App.tsx`

Есть явный переключатель:

- `Assistant`
- `Decomposition`

Поведение:

- backend pipeline общий;
- UI-представление разное;
- decomposition stack не ломается и остается доступным.

---

## 4.2 Assistant Mode UI состав

Реализовано в:

- `llm_normalizer/frontend/src/components/AssistantPanel.tsx`

Элементы:

1. Chat timeline:
   - user/assistant messages,
   - timestamp,
   - trace id для assistant сообщений.
2. Input зона:
   - поле сообщения,
   - send,
   - reset session.
3. Контекст:
   - `periodHint`
   - `businessContext`
4. Toggle:
   - `useMock`.
5. Debug drawer:
   - раскрывается per assistant message,
   - показывает raw debug JSON (`trace/fragments/routes/fallback/retrieval/normalized`).

---

## 4.3 Pipeline progress UX

Во время обработки показывается этапный status ticker:

1. `Razbirayu zapros`
2. `Proveryayu kontur`
3. `Opredelyayu marshrut`
4. `Ishchu dannye`
5. `Sobirayu otvet`

Цель: убрать ощущение “зависло” и визуализировать pipeline.

---

## 4.4 Frontend state flow

Ключевые state переменные:

- `uiMode`
- `assistantSessionId`
- `assistantConversation`
- `assistantInput`
- `assistantBusy`
- `assistantStatus`
- `assistantError`

Flow отправки:

1. optimistic append user message в chat;
2. запуск status ticker;
3. вызов `apiClient.sendAssistantMessage(...)`;
4. обновление `session_id` и полной conversation с backend;
5. остановка ticker + финальный статус.

---

## 4.5 API client для Assistant

Реализовано в:

- `llm_normalizer/frontend/src/api/client.ts`

Добавлены методы:

- `sendAssistantMessage(...)` -> `POST /api/assistant/message`
- `loadAssistantSession(sessionId)` -> `GET /api/assistant/session/:id`

---

## 5. Что сделано по требованиям ТЗ (mapping)

1. `docs/assistant_mode_spec.md` — выполнено  
2. GUI с переключателем `Assistant` / `Decomposition` — выполнено  
3. backend endpoint assistant loop — выполнено  
4. `answer_composer` слой — выполнено  
5. session-based chat history — выполнено (in-memory)  
6. debug drawer/expandable technical view — выполнено  
7. `docs/assistant_mode_flow.md` — выполнено  
8. `docs/known_limits_before_field_eval.md` — выполнено

---

## 6. Критические ограничения текущей реализации

1. **retrieval sandbox/stubbed**
   - assistant выдает план/маршрут, не full factual extraction по всем route.
2. **session memory volatile**
   - хранится только в памяти backend процесса.
3. **нет production hardening**
   - auth/tenancy/persistence/SLO не включены.
4. **composer базовый**
   - достаточен для MVP loop, но не финальный policy-grade layer.

---

## 7. Запуск и проверка на новой машине (текущий этап)

## 7.1 Backend

```powershell
cd X:\1C\NDC_1C\llm_normalizer\backend
npm install
npm run dev
```

## 7.2 Frontend

```powershell
cd X:\1C\NDC_1C\llm_normalizer\frontend
npm install
npm run dev
```

## 7.3 Открыть GUI

- `http://localhost:5174`

## 7.4 Smoke test Assistant Mode

1. Переключить mode -> `Assistant`.
2. Ввести сообщение в чат.
3. Нажать `Send`.
4. Проверить:
   - появился assistant reply;
   - появился trace id;
   - открывается debug drawer;
   - session сохраняет историю.

---

## 8. Тестовый статус к моменту фиксации

Проверки выполнены 24.03.2026:

- backend tests: `npm test` -> **21 passed**
- backend build: `npm run build` -> **OK**
- frontend build: `npm run build` -> **OK**

Также добавлен endpoint test:

- `llm_normalizer/backend/tests/assistantEndpoint.test.ts`

Покрывает:

- успешный `POST /api/assistant/message`;
- session continuity;
- `GET /api/assistant/session/:session_id`.

---

## 9. Архитектурный итог этапа

Текущий Assistant Mode — это уже **usable dialog loop**:

- user-friendly вход (чат),
- deterministic decomposition/routing ядро,
- единый backend pipeline,
- прозрачная debug-плоскость для инженерной диагностики,
- session-based continuity в рамках процесса.

Для перехода в следующий уровень (field-hardened assistant) нужен следующий блок:

- подключение route-specific factual retrieval,
- сбор 30–40 реальных полевых запросов,
- policy hardening по traces (clarification/no-route/partial quality).

