From b5ce51581fff3830605294dcb7cfe30ab8b0f83e Mon Sep 17 00:00:00 2001 From: claude_code Date: Sun, 21 Jun 2026 05:23:50 +0300 Subject: [PATCH] docs: add empty state doc for AI chat role cards --- .../backlog/ai-chat-role-cards-empty-state.md | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 docs/backlog/ai-chat-role-cards-empty-state.md diff --git a/docs/backlog/ai-chat-role-cards-empty-state.md b/docs/backlog/ai-chat-role-cards-empty-state.md new file mode 100644 index 00000000..e6610ce7 --- /dev/null +++ b/docs/backlog/ai-chat-role-cards-empty-state.md @@ -0,0 +1,165 @@ +# Выбор agent role карточками в пустом окне чата (вместо выпадающего списка) + +Контекст: при создании нового чата identity (agent role) выбирается из +выпадающего списка Mantine ``: + `apps/client/src/features/ai-chat/components/ai-chat-window.tsx:543-561`. + Значение `""` → «Universal assistant» (роль `null`); остальные опции — + `enabledRoles` (эмодзи + имя). +2. Список включённых ролей фильтруется клиентом из всех живых ролей: + `ai-chat-window.tsx:144-147` (`enabledRoles = roles.filter(r => r.enabled)`). + Источник — `useAiRolesQuery(windowOpen)` + (`apps/client/src/features/ai-chat/queries/ai-chat-query.ts:131-137`). +3. Выбранный id хранится в jotai-атоме: + `apps/client/src/features/ai-chat/atoms/ai-chat-atom.ts:23` + (`selectedAiRoleIdAtom`, `null` = Universal assistant). Сбрасывается в `null` + при «New chat»: `ai-chat-window.tsx:168-174` (`startNewChat`). +4. Выбранный id прокидывается в тред и уходит в теле первого запроса: + `ai-chat-window.tsx:570-578` (`roleId={activeChatId === null ? selectedRoleId : null}`) + → `apps/client/src/features/ai-chat/components/chat-thread.tsx:95-96, 128-138` + (`roleIdRef` → `prepareSendMessagesRequest` кладёт `roleId` в body). + Сервер учитывает `roleId` ТОЛЬКО при создании чата и фиксирует роль навсегда; + для существующего чата роль читается из строки чата (бейдж в шапке окна: + `ai-chat-window.tsx:433-440`). +5. Пустая область чата сейчас — бледный текст по центру: + `apps/client/src/features/ai-chat/components/message-list.tsx:130-140` + (`
` + `emptyState ?? t("Ask the AI agent anything...")`). + Важно: `MessageList` УЖЕ принимает произвольный `emptyState: ReactNode` + (`message-list.tsx:10-33, 64-70`) — этим пользуется публичный шэр. + +Данные роли в picker-представлении (доступны не-админам): +`id, name, emoji, description, enabled` — +`apps/server/src/core/ai-chat/roles/ai-agent-roles.service.ts:35-41, 164-173`. +То есть для карточек есть эмодзи и название (описание опционально). + +## Желаемое поведение + +- Вместо `` (`:543-561`) и импорт `Select` (`:9`, используется + только там — проверить, что `Group/Loader/Tooltip` остаются нужны). + - Собрать узел карточек только когда `activeChatId === null && + enabledRoles.length > 0`, иначе `undefined`. + - Передать его в `` (`:570-578`). Существующее + `roleId={...}` без изменений. + +3. **`chat-thread.tsx`**: + - Добавить необязательный проп `emptyState?: ReactNode` (импорт `ReactNode`) + и форварднуть в `` (`:164`). + +4. **`message-list.tsx`** — без изменений (проп `emptyState` уже поддержан). + +Иллюстративный набросок (НЕ финальный код), `AiChatWindow`: + +```tsx +// Role cards become the empty-state ONLY for a brand-new chat that has roles. +const roleCardsNode = + activeChatId === null && enabledRoles.length > 0 ? ( + + ) : undefined; +// ... + +``` + +## Краевые случаи + +- **Нет включённых ролей** → карточки не показываем (`emptyState = undefined`), + остаётся обычный дефолтный текст empty-state. +- **Существующий чат** (`activeChatId !== null`) → карточек нет; роль уже + зафиксирована и показана бейджем в шапке (`ai-chat-window.tsx:433-440`). +- **Сброс выбора** при «New chat» уже делается (`setSelectedRoleId(null)`, + `startNewChat`) — поведение сохраняется. +- **Много ролей** → контейнер с переносом и прокруткой, чтобы не ломать пустую + область чата. +- **Тёмная тема** → за счёт `-light`/`-filled` переменных Mantine цвета + корректны в обеих темах. +- **Эмодзи нет** → карточка показывает только имя (как сейчас в ``). Если решим добавить +подпись-подсказку (например «или просто начните печатать») — это один новый ключ +в `en-US/translation.json`; по умолчанию в объём не закладываю. + +## Режим работы при реализации + +Изменение нетривиальное (новый компонент + логика выбора/цветов + интеграция с +empty-state), поэтому — делегирование кодеру с обязательным последующим ревью +(`review` subagent), затем верификация перечитыванием файлов. + +## Открытые вопросы (решить перед/во время реализации) + +- [ ] Нужна ли карточка Universal assistant отдельной плиткой, или достаточно + «ничего не выбрано = дефолт»? Предлагается отдельная карточка (явный + возврат к дефолту после клика по роли) — подтвердить. +- [ ] Показывать ли `description` роли на карточке (есть в picker-view) или + только эмодзи + имя? По умолчанию — только эмодзи + имя, описание в `title`. +- [ ] Нужна ли подпись-подсказка над карточками (тогда +1 ключ локали).