14 KiB
title, aliases, created, updated, tags, related
| title | aliases | created | updated | tags | related | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Session Design — AI Psychologist App |
|
2026-05-19 | 2026-06-02 |
|
|
Session Design — AI Psychologist App
Детальный дизайн сессии: UX-флоу, механика вопросов, открытие/закрытие. Связан с: overview (раздел 5-6 — базовая структура и архитектура ботов)
1. Механика вопросов (Question Delivery)
Pipeline вопросов
Бот 2 (Analyst / "Психолог")
→ генерирует 1-2 вопроса в 3-м лице ("пользователь избегает...")
↓
Бот 1 (Narrator / "Посредник")
→ переформулирует в 1-е лицо ("ты избегаешь?")
→ на выходе: структурированный массив вопросов для UI
↓
UI алгоритм (не агент!)
→ показывает вопросы по одному в карточках
→ ждёт ответа → следующий
Ключевой принцип: раздача вопросов — детерминированный алгоритм, не LLM-вызов. Агент генерирует батч вопросов один раз → посредник переформулирует → UI сам управляет порядком.
Narrator детектирует 3-е лицо: через prompt rule ("переформулируй в 1-е лицо") — регекс не нужен.
Завершение батча вопросов → подбивка
Когда все вопросы в батче отвечены, UI передаёт агенту нумерованную подбивку ответов. Это входные данные для следующей итерации (следующий батч или инсайт).
2. Открытие сессии
Структура intro
- Персонаж-активация (анимация, 1-2 сек)
- Короткое введение — 1-2 предложения, сразу к делу, без "Давай начнём с..."
- "Крючки-активаторы" — max 2 из profile.md / последних сессий. Если нет истории — пропустить.
- Переход к теме — предложение агента или выбор пользователя
Что получает Analyst при старте
profile.md— паттерны пользователя- последние 2 сессии из
observations/ - задача: intro + max 2 крючка
3. Закрытие сессии
Последовательность (3 этапа)
Этап 1 — Structured session close (backend, не видно пользователю)
Analyst генерирует SessionCloseResult:
insight— ключевое наблюдение (1-2 предложения, 3-е лицо)sessionSummary— аналитическое резюме всей сессии (не первые реплики)profileUpdates— новые паттерны для добавления вprofile.mdpromptUpdates— обновления дляprompts.md(если применимо)
Приложение раскладывает результат по файлам через ProfileManager.
Статус: частично реализован.
insightгенерируется (Sonnet + tools + полный диалог).sessionSummary,profileUpdates,promptUpdates— НЕ реализованы (см. §12.2.G).
Этап 2 — Посредник: человечный итог (видно пользователю)
- Тёплая живая фраза, без психолого-языка
- Не повторять аналитика, не хвалить избыточно
- Упомянуть дату следующей сессии если есть расписание
Этап 3 — "One last thing" + завершение
- Открытый вопрос: "Хочешь что-то добавить?"
- Маленький текстовый input, неакцентная кнопка "Завершить"
- Если написал → агент добавляет в заметки сессии, отвечает коротко (не перезапускает сессию)
- Если упомянул перенос → сценарий планировщика (EventKit)
4. Флоу сессии целиком
ОТКРЫТИЕ
├── Анимация персонажа (1-2 сек)
├── Intro: 1-2 предложения + max 2 крючка из истории
└── Выбор темы
ДИАЛОГ
├── Analyst генерирует 1-2 вопроса (3-е лицо)
├── Narrator переформулирует → карточки (1-е лицо)
├── UI раздаёт по одному (one-card UX)
├── Пользователь отвечает → нумерованная подбивка
└── Следующий батч / инсайт
└── session_complete: true → карточка "Завершить / Продолжить"
└── hard limit: 8 ходов → принудительный readyToClose
ЗАКРЫТИЕ
├── [backend] Analyst: insight + sessionSummary + profileUpdates
├── Посредник: тёплая фраза + дата следующей сессии
├── "One last thing"
│ ├── Написал что-то → в заметки, короткий ответ
│ ├── Упомянул перенос → сценарий планировщика
│ └── Завершить (кнопка) → сессия закрыта
5. State Persistence & Session Recovery
Текущая реализация (актуально)
resumeOrStart() при открытии SessionView:
- Проверяет незавершённую сессию (
detectIncompleteSession()) .resumed→ восстанавливает карточки изsession.messages(видимые.analyst).startedAfterPartialSummary→ была стale сессия >20h → показывает partial summary, затем чистый старт.started→ обычный старт
IncompleteSessionState.isFresh — сессия считается свежей если < 20 часов.
Stale → generatePartialSummary() → completed_partial.
Что не реализовано (Stage 2)
Retention protocol: при N пропущенных сессиях подряд → реактивационный флоу с push-уведомлением.
6. Что реализовано сейчас
Актуально на 2026-06-02, коммит
4f02d565.
Пейсинг сессии
AnalystJSON.sessionComplete: Bool(backward-compatible)ProcessingResult.readyToClose([String]?, observation:)SessionManager.userTurnCount,consecutiveShortAnswerCount- Hard limit: 8 ходов → принудительный
.readyToClose continueSession()— сброс флага после "Продолжить"- Пейсинг-правила и директивы усталости в systemPrompt AnalystBot
Session Recovery
detectIncompleteSession(),resumeOrStart(),generatePartialSummary()FatigueContext,IncompleteSessionState,SessionResumeResult- SessionViewModel: восстановление карточек при
.resumed
Завершение сессии
endSession()→generateSessionInsight()(Sonnet + tools + полный диалог, без обрезки)- Агент вызывает
search_sessions,read_session,read_profileдля сравнения с историей finalInsight→ProfileManager.addInsight()немедленноsuggestedInsightпо ходу диалога →addInsight()немедленно (не теряется при X)
Агент / промпты
- NarratorBot: legit-маркер, injection guard, off-topic директива, детекция усталости/настроения
- AnalystBot: turnCount/duration/messageCount/fatigueCtx в user message; no-filepath директива
UX
- One-card UX:
CardData.isActive,appendCard(),activeCard,historyCards - История — dimmed compact cards (read-only)
TextEditorс placeholder, auto-grow (36→160pt), кнопка dismiss клавиатурыCardData.isCompletion→ quickReply "Завершить" →endSession(), "Продолжить" →continueAfterCompletion()
Тесты
- 202 теста, 0 фейлов
- Покрыто: пейсинг, усталость, injection guard, crisis, session recovery, one-card UX, insights, snapshot prompts
7. Что не реализовано (план)
7.1 Structured session close [ПРИОРИТЕТ]
Что в плане (§3, §4): Analyst возвращает структурированный объект — insight + sessionSummary + profileUpdates.
Что в коде: generateSessionInsight() возвращает только одну строку-инсайт.
profile.mdпосле сессии не обновляется новыми паттернамиprompts.mdне обновляетсяsessions/YYYY-MM-DD.mdзаполняется черезsaveSessionToProfile()где summary = первые 3 реплики пользователя, не аналитическое резюме
Решение: SessionCloseResult { insight: String, sessionSummary: String, profileUpdates: [String], promptUpdates: [String]? }.
Агент возвращает структуру → приложение раскладывает по файлам.
7.2 mood_delta → Orb visual feedback
AnalystJSON → добавить moodDelta: "declining" | "stable" | "improving".
UI: declining = холодный синий/медленный пульс, stable = нейтральный, improving = amber/живой.
7.3 Планировщик как tool
EventKit-интеграция как tool у Narrator — аналогично search_sessions / read_profile.
Дизайн-решение отложено.
7.4 Retention protocol
При N пропущенных сессиях подряд → реактивационный флоу (§5).
7.5 Android: TextEditor в Skip Fuse
Проверить поддержку TextEditor + fixedSize(horizontal:vertical:) в Skip Fuse на Android.
При необходимости заменить на TextField(axis: .vertical).
.scrollContentBackground(.hidden) уже огорожен #if os(iOS).
8. Открытые вопросы
- Планировщик — tool у Narrator (EventKit). Когда и как реализовывать?
- mood_delta — 3 значений достаточно? (declining/stable/improving)
- Android:
TextEditorв Skip Fuse — нужна проверка на устройстве
9. Протокол агента — действующие правила
NarratorBot systemPrompt содержит:
- Legit-маркер (защита от injection false positive)
- Injection guard директива
- Off-topic директива (мета-вопросы → вернуть фокус)
- Детекция усталости → передать в metadata для Analyst
- Детекция настроения →
sentimentObservationв metadata
AnalystBot systemPrompt содержит:
- Пейсинг-правила (turn_count, 4+ оборотов → оценка exhaustion, 7+ → принудительно)
- Директива при усталости:
session_complete: true,questions: [] - Директива при мета-вопросах: не объяснять архитектуру, вернуть фокус
- No-filepath директива: не упоминать пути файлов
AnalystBot tools (read-only):
search_sessions— поиск по архивуread_session— читать конкретную сессиюget_index— индекс всех сессийread_profile— профиль пользователяlist_files/read_file— дополнительные файлы профиля
10. Хранение данных (on-device)
Всё хранится через ProfileManager в Documents/UserProfile/:
| Файл | Что содержит | Кто пишет |
|---|---|---|
profile.md |
Паттерны пользователя, наблюдения | updateProfile() — пока не вызывается автоматически после сессии |
insights.md |
Инсайты по сессиям | addInsight() — пишется немедленно |
prompts.md |
Промпты/темы пользователя | не обновляется автоматически |
observations/Www.md |
Запись сессии за неделю | appendSession() |
index.md |
Индекс сессий | updateSessionIndex() |
Расписание: через системный календарь (EventKit), не отдельный файл.