Instruction file imported from clsasa1/domovoi-troll (
.github/instructions/работа с апи.instructions.md). Copyright stays with the author.
description: [14.09.2026 3:31] Арчи: Домовой Тролль — инструкция по API и интеграции LLM
- Назначение проекта «Домовой Тролль» — сатирический симулятор живого чата жильцов многоквартирного дома. Игрок попадает в домовой чат под вымышленной легендой и пытается:
- раскачать конфликт;
- сталкивать жильцов между собой;
- распространять слухи;
- провоцировать споры;
- манипулировать участниками;
- не раскрыть номер квартиры;
- не попасть под подозрение;
- не получить бан от администратора. Главная техническая задача — создать ощущение настоящего живого чата, не вызывая LLM для каждого персонажа после каждого сообщения. ───
- Общая схема работы Пользователь │ ▼ React/Vite-фронтенд │ │ POST /domovoi/api/game/message ▼ Сервер игры │ ├── хранит состояние игры ├── проверяет игровые триггеры ├── вызывает Director ├── выбирает NPC ├── вызывает Actor ├── ставит сообщение в очередь └── возвращает события клиенту │ ▼ ArionHub API Ключевой принцип: Quote Фронтенд не должен обращаться к ArionHub напрямую. API-ключ ArionHub хранится только на сервере. ───
- Кто за что отвечает 3.1. React/Vite Фронтенд отвечает только за интерфейс:
- отображает сообщения;
- отправляет сообщения игрока на сервер;
- показывает статус «печатает…»;
- отображает ответы NPC;
- показывает Tension и Suspicion;
- воспроизводит очередь игровых событий;
- показывает финальный экран, бан или победу. Фронтенд не должен:
- хранить API-ключ;
- импортировать серверный LLM-клиент;
- самостоятельно выбирать NPC;
- сам менять Tension и Suspicion;
- хранить скрытые цели персонажей;
- отправлять запросы напрямую в ArionHub. Фронтенд должен обращаться только к API игры: fetch('/domovoi/api/game/message') ─── 3.2. Сервер игры Сервер является главным оркестратором игры. Он отвечает за:
- создание игровых сессий;
- хранение текущего состояния;
- профили NPC;
- легенду игрока;
- проверку номеров квартир;
- запуск игровых триггеров;
- вызов Director;
- вызов Actor;
- валидацию JSON;
- изменение Tension и Suspicion;
- очередь событий;
- обработку ошибок;
- защиту API-ключа. Именно сервер решает, что реально произошло в игре. Нельзя доверять значениям состояния, которые присылает браузер. ─── 3.3. Director Director — это дешёвая и быстрая LLM-модель, которая принимает игровые решения. Он получает:
- последнее сообщение игрока;
- последние сообщения чата;
- текущий Tension;
- текущий Suspicion;
- активные профили NPC;
- легенду игрока;
- активные конфликты. Director решает:
- нужно ли отвечать;
- какой NPC ответит;
- кому он отвечает;
- будет ли конфликт усилен или ослаблен;
- нужно ли вызвать администратора;
- насколько изменить Tension;
- насколько изменить Suspicion;
- через сколько времени публиковать сообщение;
- какую директиву передать Actor. Director не должен генерировать длинную реплику. Его задача — принять структурированное решение. ─── 3.4. Actor Actor — это LLM, которая пишет реплику конкретного персонажа. Actor получает:
- профиль выбранного NPC;
- архетип персонажа;
- манеру речи;
- любимые фразы;
- отношение к игроку;
- директиву Director;
- небольшой контекст последних сообщений. Actor возвращает только текст одного сообщения. Actor не должен:
- выбирать другого NPC;
- самостоятельно менять Tension;
- самостоятельно менять Suspicion;
- писать сообщения за нескольких персонажей;
- возвращать JSON Director;
- объяснять своё решение;
- писать литературный рассказ вместо сообщения в чате. ─── 3.5. Event Queue Очередь событий отвечает за реалистичный темп чата. Сообщение NPC проходит состояния: idle → typing → sent Пример: Director выбрал Людмилу ↓ показать «Людмила Викторовна печатает…» ↓ подождать 2–5 секунд ↓ показать сообщение ↓ убрать индикатор печати Запрос к LLM не должен ждать эти 2–5 секунд. Сервер получает ответ заранее, а задержка применяется при публикации события пользователю. Игрок в это время может:
- отправить новое сообщение;
- перебить NPC;
- ответить другому персонажу;
- написать несколько сообщений подряд;
- ничего не делать. ───
- Текущая интеграция ArionHub В репозитории используется OpenAI-compatible SDK: import OpenAI from 'openai' Текущие настройки проекта: const ARIONHUB_BASE_URL = 'https://api.arionhub.pro/v1' const DIRECTOR_MODEL = 'china-gpt-5.6-luna' const ACTOR_MODEL = 'grok-4.6' Важно: адрес в текущем коде именно: https://api.arionhub.pro/v1 Перед production-запуском необходимо проверить, что модели china-gpt-5.6-luna и grok-4.6 доступны в аккаунте ArionHub. Создание клиента const client = new OpenAI({ baseURL: 'https://api.arionhub.pro/v1', apiKey: process.env.ARIONHUB_API_KEY, }) API-ключ берётся из переменной окружения: ARIONHUB_API_KEY=*** Ключ нельзя помещать в: VITE_ARIONHUB_API_KEY или любую другую переменную, которая попадёт в браузерный bundle. ───
- Где находятся основные модули src/llm/arionhubClient.ts Отвечает за:
- создание клиента OpenAI-compatible API;
- вызов Director;
- вызов Actor;
- получение ответа модели;
- разбор JSON;
- валидацию ответа Director. В текущей реализации есть функции: callDirector(context, options?) callActor(npcProfile, directive, options?) src/llm/directorEngine.ts Отвечает за:
- тип входного контекста Director;
- Zod-схему ответа;
- системный промпт Director. src/llm/actorEngine.ts Отвечает за:
- профили персонажей;
- стили речи;
- генерацию промпта Actor;
- очистку текста ответа. ───
- Персонажи В текущем проекте предусмотрены следующие NPC. Людмила Викторовна ID: ludmila Квартира: 48 Архетип: пенсионерка и хранительница порядка Характер:
- считает себя главным экспертом в чате;
- любит обвинять соседей;
- подозревает новых участников;
- использует многоточия;
- иногда пишет капсом;
- любит фразы «совесть имейте» и «участковому наберу». Сергей Ремонт ID: sergey_drill Квартира: 72 Архетип: мужик со сверлом Характер:
- постоянно говорит о ремонте;
- требует соблюдать закон о тишине;
- раздражается на поучения;
- может неожиданно поддержать игрока;
- пишет эмоционально и с восклицаниями. Любимые фразы: «по закону тишины» «не учите меня жить» Наталья Белова ID: natalya_activist Квартира: 31 Архетип: активистка ЖКХ Характер:
- требует доказательства;
- собирает фотофиксацию;
- пишет формально;
- угрожает обращением в суд;
- может начать конфликтовать при высоком Tension. Любимые фразы: «фотофиксация приложена» «в суд направлю» Администратор ID: admin Архетип: уставший администратор Характер:
- следит за порядком;
- требует представиться;
- спрашивает номер квартиры;
- выдаёт предупреждения;
- может инициировать бан. Любимые фразы: «предупреждение» «ещё одно сообщение — бан» ───
- Тип профиля NPC export type NpcPersonality = { id: string name: string archetype: string speechProfile: { capsLockProbability: number typoRate: number punctuationStyle: | 'multiple_dots' | 'excessive_exclamation' | 'no_punctuation' | 'formal' favoritePhrases: string[] } currentAttitudeToPlayer: number } Пример: const ludmila: NpcPersonality = { id: 'ludmila', name: 'Людмила Викторовна (кв. 48)', archetype: 'пенсионерка и хранительница порядка', … [14.09.2026 3:31] Арчи: - «кто ты?»;
- «из какой квартиры?»;
- «какой этаж?»;
- «кто тебя добавил?»;
- «админ»;
- «бан»;
- изменение легенды;
- упоминание номера квартиры;
- совпадение номера с квартирой NPC. Событие «Самозванец» Если игрок называет квартиру, которая принадлежит уже существующему NPC, запускается специальное событие: { "type": "system_event", "event": "impostor_triggered", "targetNpcId": "ludmila", "suspicionDelta": 20 } Сервер должен сам определить совпадение номера. LLM может решить, как персонажи отреагируют, но сам факт совпадения нельзя полностью отдавать модели. ───
- Когда LLM вызывать не нужно Не нужно вызывать Director и Actor для:
- «+»;
- «согласна»;
- «ужас»;
- случайных стикеров;
- коротких бытовых реакций;
- фоновых сообщений;
- сообщений о сантехнике;
- сообщений о парковке;
- сообщений о воде;
- технических событий;
- индикатора печати;
- health-check. Для этого используется Static Pool: [ { "text": "+", "actorId": "natalya_activist" }, { "text": "а у кого номер сантехника?", "actorId": "sergey_drill" }, { "text": "опять воду отключили...", "actorId": "ludmila" }, { "text": "скиньте протокол собрания", "actorId": "natalya_activist" } ] При высоком Tension можно выбирать более конфликтные фоновые сообщения. ───
- Подключение API во фронтенде Фронтенд не должен импортировать: arionhubClient.ts directorEngine.ts actorEngine.ts Он должен вызывать API игры: const response = await fetch( '/domovoi/api/game/message', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId, text, replyToMessageId: replyToMessageId ?? null, messageType: 'text', }), }, )
if (!response.ok) { throw new Error('Game API request failed') }
const result = await response.json() Клиент обрабатывает events: playerMessage → сразу показать сообщение игрока typing_start → показать «печатает…» npc_message → показать после delayMs typing_stop → убрать индикатор system_event → показать игровое событие game_over → показать финальный экран ─── 21. Обработка ошибок Ошибка 401 или 403 Возможные причины:
- отсутствует API-ключ;
- неправильный API-ключ;
- нет доступа к модели;
- закончился баланс. Нельзя отправлять ключ в ответе или логах. Ошибка 429 Возможные причины:
- превышен rate limit;
- слишком много запросов;
- слишком частые действия игроков. Нужно:
- ограничить частоту запросов;
- использовать retry с задержкой;
- не запускать несколько Director одновременно для одной сессии. Ошибка 500, 502 или 503 Нужно:
- записать техническую ошибку без секрета;
- использовать fallback Director или Actor;
- не оставлять чат в бесконечном состоянии typing. Timeout Если Actor не ответил вовремя:
- удалить пользователя из activeTypingUsers;
- записать техническую ошибку;
- использовать локальную fallback-реплику;
- продолжить игровой цикл. Некорректный JSON Director Порядок обработки:
- удалить Markdown-обёртку;
- попытаться разобрать JSON;
- проверить через Zod;
- если схема не совпала — не применять ответ;
- использовать локальный fallback;
- записать причину ошибки без секретов. ───
- Защита API На сервере необходимо добавить:
- ограничение длины сообщения;
- rate limit;
- timeout для LLM;
- ограничение числа retry;
- проверку sessionId;
- CORS только для собственного домена;
- серверную валидацию всех входных данных;
- маскирование API-ключей;
- запрет публикации внутренних полей;
- очистку ответа Actor. Клиенту нельзя позволять изменять:
- tension;
- suspicion;
- список NPC;
- отношение NPC;
- статус игры;
- решение Director;
- легенду после её подтверждения сервером. ───
- Переменные окружения На сервере: ARIONHUB_API_KEY=*** Файл .env должен:
- находиться только на сервере;
- иметь права 600;
- быть добавлен в .gitignore;
- не попадать в production bundle;
- не выводиться в логах. Проверка: git check-ignore .env Проверка прав: stat -c '%A %n' .env Ожидается: -rw------- ───
- Порядок внедрения Шаг 1. Унифицировать Director Привести directorEngine.ts и arionhubClient.ts к одной схеме. Рекомендуемые поля: selectedActorId actionType targetNpcId replyToMessageId tensionDelta suspicionDelta actorDirective recommendedDelayMs Шаг 2. Убрать LLM из фронтенда Проверить, что arionhubClient.ts не попадает в Vite bundle. Фронтенд должен использовать только: /domovoi/api/... Шаг 3. Реализовать /game/start Сделать создание:
- sessionId;
- легенды игрока;
- начального состояния;
- начальных метрик. Шаг 4. Реализовать /game/message Сначала подключить только Director и проверить:
- JSON;
- выбор NPC;
- изменение Tension;
- изменение Suspicion. Шаг 5. Подключить Actor Проверить:
- стиль сообщений;
- длину;
- очистку;
- fallback;
- отсутствие ответа от имени нескольких NPC. Шаг 6. Добавить очередь Добавить:
- typing_start;
- задержку;
- npc_message;
- typing_stop;
- перебивание сообщений. Шаг 7. Добавить локальные триггеры Добавить:
- проверку квартиры;
- событие «Самозванец»;
- вопросы администратора;
- бан. Шаг 8. Добавить Static Pool Фоновые сообщения должны работать без вызова LLM. Шаг 9. Подключить финальный экран Добавить:
- разоблачение;
- бан;
- победу;
- итоговый Troll Score;
- карточку результата. ───
- Smoke-тест API
Проверка сервера:
curl -i https://clsasa.ru/domovoi/api/health
Создание игры:
curl -i -X POST
https://clsasa.ru/domovoi/api/game/start
-H 'Content-Type: application/json'
-d '{}' Отправка сообщения: curl -i -X POST
https://clsasa.ru/domovoi/api/game/message
-H 'Content-Type: application/json'
-d '{ "sessionId": "SESSION_ID", "text": "Кто отвечает за ремонт?", "messageType": "text" }' Проверить:
- HTTP-код;
- наличие events;
- наличие выбранного NPC;
- изменение Tension;
- изменение Suspicion;
- появление сообщения Actor;
- отсутствие API-ключа;
- отсутствие системного промпта;
- отсутствие internalReasoning;
- отсутствие вечного typing. ───
- Критические ошибки, которых нельзя допускать
- Вызывать ArionHub напрямую из React.
- Использовать VITE_ARIONHUB_API_KEY.
- Хранить ключ в Git.
- Вызывать LLM для каждого NPC после каждого сообщения.
- Передавать в LLM всю историю игры.
- Использовать две разные схемы Director.
- Публиковать пользователю внутреннее reasoning.
- Позволять клиенту менять Tension и Suspicion.
- Оставлять NPC в статусе «печатает…» после timeout.
- Логировать заголовок Authorization.
- Считать проект рабочим только по успешному npm run build.
- Не проверять совпадение номера квартиры программно.
- Давать Actor возможность писать от имени нескольких персонажей.
- Отправлять секретные переменные во фронтенд.
- Не иметь fallback при сбое ArionHub. Главная архитектурная идея: Quote Director принимает игровое решение, Actor пишет одну реплику, сервер проверяет результат, а Event Queue создаёт ощущение живого чата. Фоновые сообщения работают без LLM, чтобы снизить стоимость и задержку.
applyTo: '[14.09.2026 3:31] Арчи: Домовой Тролль — инструкция по API и интеграции LLM
- Назначение проекта «Домовой Тролль» — сатирический симулятор живого чата жильцов многоквартирного дома. Игрок попадает в домовой чат под вымышленной легендой и пытается:
- раскачать конфликт;
- сталкивать жильцов между собой;
- распространять слухи;
- провоцировать споры;
- манипулировать участниками;
- не раскрыть номер квартиры;
- не попасть под подозрение;
- не получить бан от администратора. Главная техническая задача — создать ощущение настоящего живого чата, не вызывая LLM для каждого персонажа после каждого сообщения. ───
- Общая схема работы Пользователь │ ▼ React/Vite-фронтенд │ │ POST /domovoi/api/game/message ▼ Сервер игры │ ├── хранит состояние игры ├── проверяет игровые триггеры ├── вызывает Director ├── выбирает NPC ├── вызывает Actor ├── ставит сообщение в очередь └── возвращает события клиенту │ ▼ ArionHub API Ключевой принцип: Quote Фронтенд не должен обращаться к ArionHub напрямую. API-ключ ArionHub хранится только на сервере. ───
- Кто за что отвечает 3.1. React/Vite Фронтенд отвечает только за интерфейс:
- отображает сообщения;
- отправляет сообщения игрока на сервер;
- показывает статус «печатает…»;
- отображает ответы NPC;
- показывает Tension и Suspicion;
- воспроизводит очередь игровых событий;
- показывает финальный экран, бан или победу. Фронтенд не должен:
- хранить API-ключ;
- импортировать серверный LLM-клиент;
- самостоятельно выбирать NPC;
- сам менять Tension и Suspicion;
- хранить скрытые цели персонажей;
- отправлять запросы напрямую в ArionHub. Фронтенд должен обращаться только к API игры: fetch('/domovoi/api/game/message') ─── 3.2. Сервер игры Сервер является главным оркестратором игры. Он отвечает за:
- создание игровых сессий;
- хранение текущего состояния;
- профили NPC;
- легенду игрока;
- проверку номеров квартир;
- запуск игровых триггеров;
- вызов Director;
- вызов Actor;
- валидацию JSON;
- изменение Tension и Suspicion;
- очередь событий;
- обработку ошибок;
- защиту API-ключа. Именно сервер решает, что реально произошло в игре. Нельзя доверять значениям состояния, которые присылает браузер. ─── 3.3. Director Director — это дешёвая и быстрая LLM-модель, которая принимает игровые решения. Он получает:
- последнее сообщение игрока;
- последние сообщения чата;
- текущий Tension;
- текущий Suspicion;
- активные профили NPC;
- легенду игрока;
- активные конфликты. Director решает:
- нужно ли отвечать;
- какой NPC ответит;
- кому он отвечает;
- будет ли конфликт усилен или ослаблен;
- нужно ли вызвать администратора;
- насколько изменить Tension;
- насколько изменить Suspicion;
- через сколько времени публиковать сообщение;
- какую директиву передать Actor. Director не должен генерировать длинную реплику. Его задача — принять структурированное решение. ─── 3.4. Actor Actor — это LLM, которая пишет реплику конкретного персонажа. Actor получает:
- профиль выбранного NPC;
- архетип персонажа;
- манеру речи;
- любимые фразы;
- отношение к игроку;
- директиву Director;
- небольшой контекст последних сообщений. Actor возвращает только текст одного сообщения. Actor не должен:
- выбирать другого NPC;
- самостоятельно менять Tension;
- самостоятельно менять Suspicion;
- писать сообщения за нескольких персонажей;
- возвращать JSON Director;
- объяснять своё решение;
- писать литературный рассказ вместо сообщения в чате. ─── 3.5. Event Queue Очередь событий отвечает за реалистичный темп чата. Сообщение NPC проходит состояния: idle → typing → sent Пример: Director выбрал Людмилу ↓ показать «Людмила Викторовна печатает…» ↓ подождать 2–5 секунд ↓ показать сообщение ↓ убрать индикатор печати Запрос к LLM не должен ждать эти 2–5 секунд. Сервер получает ответ заранее, а задержка применяется при публикации события пользователю. Игрок в это время может:
- отправить новое сообщение;
- перебить NPC;
- ответить другому персонажу;
- написать несколько сообщений подряд;
- ничего не делать. ───
- Текущая интеграция ArionHub В репозитории используется OpenAI-compatible SDK: import OpenAI from 'openai' Текущие настройки проекта: const ARIONHUB_BASE_URL = 'https://api.arionhub.pro/v1' const DIRECTOR_MODEL = 'china-gpt-5.6-luna' const ACTOR_MODEL = 'grok-4.6' Важно: адрес в текущем коде именно: https://api.arionhub.pro/v1 Перед production-запуском необходимо проверить, что модели china-gpt-5.6-luna и grok-4.6 доступны в аккаунте ArionHub. Создание клиента const client = new OpenAI({ baseURL: 'https://api.arionhub.pro/v1', apiKey: process.env.ARIONHUB_API_KEY, }) API-ключ берётся из переменной окружения: ARIONHUB_API_KEY=*** Ключ нельзя помещать в: VITE_ARIONHUB_API_KEY или любую другую переменную, которая попадёт в браузерный bundle. ───
- Где находятся основные модули src/llm/arionhubClient.ts Отвечает за:
- создание клиента OpenAI-compatible API;
- вызов Director;
- вызов Actor;
- получение ответа модели;
- разбор JSON;
- валидацию ответа Director. В текущей реализации есть функции: callDirector(context, options?) callActor(npcProfile, directive, options?) src/llm/directorEngine.ts Отвечает за:
- тип входного контекста Director;
- Zod-схему ответа;
- системный промпт Director. src/llm/actorEngine.ts Отвечает за:
- профили персонажей;
- стили речи;
- генерацию промпта Actor;
- очистку текста ответа. ───
- Персонажи В текущем проекте предусмотрены следующие NPC. Людмила Викторовна ID: ludmila Квартира: 48 Архетип: пенсионерка и хранительница порядка Характер:
- считает себя главным экспертом в чате;
- любит обвинять соседей;
- подозревает новых участников;
- использует многоточия;
- иногда пишет капсом;
- любит фразы «совесть имейте» и «участковому наберу». Сергей Ремонт ID: sergey_drill Квартира: 72 Архетип: мужик со сверлом Характер:
- постоянно говорит о ремонте;
- требует соблюдать закон о тишине;
- раздражается на поучения;
- может неожиданно поддержать игрока;
- пишет эмоционально и с восклицаниями. Любимые фразы: «по закону тишины» «не учите меня жить» Наталья Белова ID: natalya_activist Квартира: 31 Архетип: активистка ЖКХ Характер:
- требует доказательства;
- собирает фотофиксацию;
- пишет формально;
- угрожает обращением в суд;
- может начать конфликтовать при высоком Tension. Любимые фразы: «фотофиксация приложена» «в суд направлю» Администратор ID: admin Архетип: уставший администратор Характер:
- следит за порядком;
- требует представиться;
- спрашивает номер квартиры;
- выдаёт предупреждения;
- может инициировать бан. Любимые фразы: «предупреждение» «ещё одно сообщение — бан» ───
- Тип профиля NPC export type NpcPersonality = { id: string name: string archetype: string speechProfile: { capsLockProbability: number typoRate: number punctuationStyle: | 'multiple_dots' | 'excessive_exclamation' | 'no_punctuation' | 'formal' favoritePhrases: string[] } currentAttitudeToPlayer: number } Пример: const ludmila: NpcPersonality = { id: 'ludmila', name: 'Людмила Викторовна (кв. 48)', archetype: 'пенсионерка и хранительница порядка', … [14.09.2026 3:31] Арчи: - «кто ты?»;
- «из какой квартиры?»;
- «какой этаж?»;
- «кто тебя добавил?»;
- «админ»;
- «бан»;
- изменение легенды;
- упоминание номера квартиры;
- совпадение номера с квартирой NPC. Событие «Самозванец» Если игрок называет квартиру, которая принадлежит уже существующему NPC, запускается специальное событие: { "type": "system_event", "event": "impostor_triggered", "targetNpcId": "ludmila", "suspicionDelta": 20 } Сервер должен сам определить совпадение номера. LLM может решить, как персонажи отреагируют, но сам факт совпадения нельзя полностью отдавать модели. ───
- Когда LLM вызывать не нужно Не нужно вызывать Director и Actor для:
- «+»;
- «согласна»;
- «ужас»;
- случайных стикеров;
- коротких бытовых реакций;
- фоновых сообщений;
- сообщений о сантехнике;
- сообщений о парковке;
- сообщений о воде;
- технических событий;
- индикатора печати;
- health-check. Для этого используется Static Pool: [ { "text": "+", "actorId": "natalya_activist" }, { "text": "а у кого номер сантехника?", "actorId": "sergey_drill" }, { "text": "опять воду отключили...", "actorId": "ludmila" }, { "text": "скиньте протокол собрания", "actorId": "natalya_activist" } ] При высоком Tension можно выбирать более конфликтные фоновые сообщения. ───
- Подключение API во фронтенде Фронтенд не должен импортировать: arionhubClient.ts directorEngine.ts actorEngine.ts Он должен вызывать API игры: const response = await fetch( '/domovoi/api/game/message', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ sessionId, text, replyToMessageId: replyToMessageId ?? null, messageType: 'text', }), }, )
if (!response.ok) { throw new Error('Game API request failed') }
const result = await response.json() Клиент обрабатывает events: playerMessage → сразу показать сообщение игрока typing_start → показать «печатает…» npc_message → показать после delayMs typing_stop → убрать индикатор system_event → показать игровое событие game_over → показать финальный экран ─── 21. Обработка ошибок Ошибка 401 или 403 Возможные причины:
- отсутствует API-ключ;
- неправильный API-ключ;
- нет доступа к модели;
- закончился баланс. Нельзя отправлять ключ в ответе или логах. Ошибка 429 Возможные причины:
- превышен rate limit;
- слишком много запросов;
- слишком частые действия игроков. Нужно:
- ограничить частоту запросов;
- использовать retry с задержкой;
- не запускать несколько Director одновременно для одной сессии. Ошибка 500, 502 или 503 Нужно:
- записать техническую ошибку без секрета;
- использовать fallback Director или Actor;
- не оставлять чат в бесконечном состоянии typing. Timeout Если Actor не ответил вовремя:
- удалить пользователя из activeTypingUsers;
- записать техническую ошибку;
- использовать локальную fallback-реплику;
- продолжить игровой цикл. Некорректный JSON Director Порядок обработки:
- удалить Markdown-обёртку;
- попытаться разобрать JSON;
- проверить через Zod;
- если схема не совпала — не применять ответ;
- использовать локальный fallback;
- записать причину ошибки без секретов. ───
- Защита API На сервере необходимо добавить:
- ограничение длины сообщения;
- rate limit;
- timeout для LLM;
- ограничение числа retry;
- проверку sessionId;
- CORS только для собственного домена;
- серверную валидацию всех входных данных;
- маскирование API-ключей;
- запрет публикации внутренних полей;
- очистку ответа Actor. Клиенту нельзя позволять изменять:
- tension;
- suspicion;
- список NPC;
- отношение NPC;
- статус игры;
- решение Director;
- легенду после её подтверждения сервером. ───
- Переменные окружения На сервере: ARIONHUB_API_KEY=*** Файл .env должен:
- находиться только на сервере;
- иметь права 600;
- быть добавлен в .gitignore;
- не попадать в production bundle;
- не выводиться в логах. Проверка: git check-ignore .env Проверка прав: stat -c '%A %n' .env Ожидается: -rw------- ───
- Порядок внедрения Шаг 1. Унифицировать Director Привести directorEngine.ts и arionhubClient.ts к одной схеме. Рекомендуемые поля: selectedActorId actionType targetNpcId replyToMessageId tensionDelta suspicionDelta actorDirective recommendedDelayMs Шаг 2. Убрать LLM из фронтенда Проверить, что arionhubClient.ts не попадает в Vite bundle. Фронтенд должен использовать только: /domovoi/api/... Шаг 3. Реализовать /game/start Сделать создание:
- sessionId;
- легенды игрока;
- начального состояния;
- начальных метрик. Шаг 4. Реализовать /game/message Сначала подключить только Director и проверить:
- JSON;
- выбор NPC;
- изменение Tension;
- изменение Suspicion. Шаг 5. Подключить Actor Проверить:
- стиль сообщений;
- длину;
- очистку;
- fallback;
- отсутствие ответа от имени нескольких NPC. Шаг 6. Добавить очередь Добавить:
- typing_start;
- задержку;
- npc_message;
- typing_stop;
- перебивание сообщений. Шаг 7. Добавить локальные триггеры Добавить:
- проверку квартиры;
- событие «Самозванец»;
- вопросы администратора;
- бан. Шаг 8. Добавить Static Pool Фоновые сообщения должны работать без вызова LLM. Шаг 9. Подключить финальный экран Добавить:
- разоблачение;
- бан;
- победу;
- итоговый Troll Score;
- карточку результата. ───
- Smoke-тест API
Проверка сервера:
curl -i https://clsasa.ru/domovoi/api/health
Создание игры:
curl -i -X POST
https://clsasa.ru/domovoi/api/game/start
-H 'Content-Type: application/json'
-d '{}' Отправка сообщения: curl -i -X POST
https://clsasa.ru/domovoi/api/game/message
-H 'Content-Type: application/json'
-d '{ "sessionId": "SESSION_ID", "text": "Кто отвечает за ремонт?", "messageType": "text" }' Проверить:
- HTTP-код;
- наличие events;
- наличие выбранного NPC;
- изменение Tension;
- изменение Suspicion;
- появление сообщения Actor;
- отсутствие API-ключа;
- отсутствие системного промпта;
- отсутствие internalReasoning;
- отсутствие вечного typing. ───
- Критические ошибки, которых нельзя допускать
- Вызывать ArionHub напрямую из React.
- Использовать VITE_ARIONHUB_API_KEY.
- Хранить ключ в Git.
- Вызывать LLM для каждого NPC после каждого сообщения.
- Передавать в LLM всю историю игры.
- Использовать две разные схемы Director.
- Публиковать пользователю внутреннее reasoning.
- Позволять клиенту менять Tension и Suspicion.
- Оставлять NPC в статусе «печатает…» после timeout.
- Логировать заголовок Authorization.
- Считать проект рабочим только по успешному npm run build.
- Не проверять совпадение номера квартиры программно.
- Давать Actor возможность писать от имени нескольких персонажей.
- Отправлять секретные переменные во фронтенд.
- Не иметь fallback при сбое ArionHub. Главная архитектурная идея: Quote Director принимает игровое решение, Actor пишет одну реплику, сервер проверяет результат, а Event Queue создаёт ощущение живого чата. Фоновые сообщения работают без LLM, чтобы снизить стоимость и задержку.' # when provided, instructions will automatically be added to the request context when the pattern matches an attached file
Provide project context and coding guidelines that AI should follow when generating code, answering questions, or reviewing changes.