feat(public-share): selectable agent-role identity + fix floating-icon overlap #25

Merged
Ghost merged 1 commits from feat/share-assistant-identity-and-branding into develop 2026-06-20 19:59:49 +03:00

Что сделано

Два фикса для фичи «анонимный AI-ассистент на публичных шарах».

1. Выбор identity (agent role) для анонимного ассистента

  • Новая настройка воркспейса publicShareAssistantRoleId (под settings.ai.provider, пустое = встроенная заблокированная персона). Админ выбирает, какую роль-«личность» принимает анонимный ассистент.
  • Роль разрешается на сервере авторитетно: AiAgentRoleRepo.findById(roleId, workspaceId) (scoped по воркспейсу, soft-delete aware); отсутствующая/отключённая роль → fallback на встроенную персону.
  • instructions роли ЗАМЕНЯЮТ встроенный PERSONA, но неизменяемый SAFETY_FRAMEWORK по-прежнему всегда добавляется — граница безопасности остаётся областью видимости инструментов (дерево шары).
  • Опциональный model-override роли имеет приоритет над дешёвым publicShareChatModel.
  • Проброс через UpdateAiSettingsDtoai-settings.service (update whitelist) → второй whitelist ALLOWED в workspace.reporesolve()/getMasked() → разрешение роли на стриме → промпт/модель.
  • UI: новый Select «Assistant identity» в блоке «Public share assistant» (список включённых ролей + пункт «Built-in assistant persona»; сохранённая, но отключённая роль показывается явно с пометкой «(disabled)», чтобы поле не было пустым).

2. Фикс перекрытия плавающей иконки + переименование

  • AI-FAB (share-ai-widget.tsx) и кнопка брендинга (share-branding.tsx) обе были Affix в правом нижнем углу и накладывались. FAB поднят (bottom: 80) и стоит НАД брендингом (bottom: 20), оба справа — без наложения и в одностраничных, и в многостраничных шарах (брендинг остаётся справа, не задевает левый navbar).
  • «Powered by Docmost» → «Powered by Gitmost», ссылка переведена на репозиторий gitmost.

Вне scope

  • Не трогал серверную область видимости инструментов и CASL-границу — роль влияет только на персону и (опционально) модель.
  • Случай полностью УДАЛЁННой (не просто отключённой) сохранённой роли намеренно отображается в Select пустым — id на сервере трактуется как built-in.

Верификация

  • pnpm --filter server test -- public-share-chat — 39/39 passed (включая новые тесты: замена персоны ролью при сохранённом safety-framework, edge-cases resolveShareRole, приоритет model-override).
  • pnpm --filter client exec tsc --noEmit — exit 0.
  • pnpm --filter server build — exit 0 (typecheck сервера).
  • ESLint в этом worktree не запускается из-за отсутствующего артефакта зависимости @tanstack/eslint-plugin-query (проблема установки в worktree, не связана с изменениями).

Ревью

Прошло два прохода review-субагента: первый дал 2 не-блокирующих замечания (наложение брендинга на левый navbar в многостраничных шарах; пустой Select для отключённой роли) — оба исправлены; повторное ревью — APPROVE.

## Что сделано Два фикса для фичи «анонимный AI-ассистент на публичных шарах». ### 1. Выбор identity (agent role) для анонимного ассистента - Новая настройка воркспейса `publicShareAssistantRoleId` (под `settings.ai.provider`, пустое = встроенная заблокированная персона). Админ выбирает, какую роль-«личность» принимает анонимный ассистент. - Роль разрешается на сервере авторитетно: `AiAgentRoleRepo.findById(roleId, workspaceId)` (scoped по воркспейсу, soft-delete aware); отсутствующая/отключённая роль → fallback на встроенную персону. - `instructions` роли ЗАМЕНЯЮТ встроенный `PERSONA`, но неизменяемый `SAFETY_FRAMEWORK` по-прежнему всегда добавляется — граница безопасности остаётся областью видимости инструментов (дерево шары). - Опциональный model-override роли имеет приоритет над дешёвым `publicShareChatModel`. - Проброс через `UpdateAiSettingsDto` → `ai-settings.service` (update whitelist) → второй whitelist `ALLOWED` в `workspace.repo` → `resolve()`/`getMasked()` → разрешение роли на стриме → промпт/модель. - UI: новый `Select` «Assistant identity» в блоке «Public share assistant» (список включённых ролей + пункт «Built-in assistant persona»; сохранённая, но отключённая роль показывается явно с пометкой «(disabled)», чтобы поле не было пустым). ### 2. Фикс перекрытия плавающей иконки + переименование - AI-FAB (`share-ai-widget.tsx`) и кнопка брендинга (`share-branding.tsx`) обе были `Affix` в правом нижнем углу и накладывались. FAB поднят (`bottom: 80`) и стоит НАД брендингом (`bottom: 20`), оба справа — без наложения и в одностраничных, и в многостраничных шарах (брендинг остаётся справа, не задевает левый navbar). - «Powered by Docmost» → «Powered by Gitmost», ссылка переведена на репозиторий gitmost. ## Вне scope - Не трогал серверную область видимости инструментов и CASL-границу — роль влияет только на персону и (опционально) модель. - Случай полностью УДАЛЁННой (не просто отключённой) сохранённой роли намеренно отображается в Select пустым — id на сервере трактуется как built-in. ## Верификация - `pnpm --filter server test -- public-share-chat` — 39/39 passed (включая новые тесты: замена персоны ролью при сохранённом safety-framework, edge-cases `resolveShareRole`, приоритет model-override). - `pnpm --filter client exec tsc --noEmit` — exit 0. - `pnpm --filter server build` — exit 0 (typecheck сервера). - ESLint в этом worktree не запускается из-за отсутствующего артефакта зависимости `@tanstack/eslint-plugin-query` (проблема установки в worktree, не связана с изменениями). ## Ревью Прошло два прохода review-субагента: первый дал 2 не-блокирующих замечания (наложение брендинга на левый navbar в многостраничных шарах; пустой Select для отключённой роли) — оба исправлены; повторное ревью — APPROVE.
Ghost added 1 commit 2026-06-20 19:56:27 +03:00
Anonymous public-share AI assistant:
- Add a workspace setting `publicShareAssistantRoleId` so an admin can pick which
  agent role (identity/persona) the anonymous assistant adopts. The role's
  instructions REPLACE the built-in persona while the immutable safety framework
  is still always appended; the role's optional model override takes precedence
  over the cheap publicShareChatModel. Resolved server-authoritatively
  (workspace-scoped, soft-delete aware; disabled/missing roles fall back to the
  built-in persona, so the tool scope remains the real security boundary).
- Plumb the field through the update DTO, ai-settings service, the workspace.repo
  ALLOWED whitelist, resolve()/getMasked(), stream-time role resolution and the
  prompt/model, plus the settings UI: a new "Assistant identity" Select listing
  enabled roles (and surfacing a saved-but-disabled role explicitly).

Public-share branding / floating icon:
- Fix the AI assistant FAB overlapping the "Powered by ..." button (both were
  Affixed bottom-right): stack the FAB above the bottom-right branding.
- Rename "Powered by Docmost" -> "Powered by Gitmost" and point the link at the
  gitmost repo.

Tests: extend public-share-chat.spec (role persona replacement still appends the
safety framework, resolveShareRole edge cases, model-override precedence).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ghost merged commit 6128920264 into develop 2026-06-20 19:59:49 +03:00
Ghost deleted branch feat/share-assistant-identity-and-branding 2026-06-20 19:59:49 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#25