24 KiB
Mistral Chat App - Development Context
Project Overview
Android-приложение для чата с Mistral AI. Перспективный проект с развитием в сторону AI-агента с памятью, tools и автономной работой.
Основные технологии:
- Kotlin + Android (minSdk 26, targetSdk 34)
- Room + SQLCipher (encrypted database)
- OkHttp для API
- Material Design 3
- Russian language UI
Расположение проекта:
/Users/alexabudaev/Documents/Zed/mistral-chat-app/
⚠️ ВАЖНО: Принципы разработки
- Приложение должно работать БЕЗ платных подписок и инвестиций
- Всегда использовать собственные разработки или бесплатные решения
- Не рассчитывать на имеющиеся платные API при планировании функций
- Сначала находим бесплатное решение, потом реализуем
- Если что-то невозможно сделать без платных API или ты не можешь понять задачу - говори честно!
- При планировании любого следующего этапа следует тщательно анализировать возможность реализовать ту или иную функцию не только исходя из программной совместимости, но и с учётом наличия бесплатных версий необходимых сервисов, API и других продуктов (или возможности написать собственное решение)
Completed Work
✅ Core Features
- Чат с Mistral API (Chat Completion)
- Управление профилями (до 10 профилей)
- Управление сессиями (множественные чаты)
- Генерация названия сессии - после 2-го сообщения AI генерирует краткое название (3-5 слов)
- Шифрованное хранилище (SQLCipher + EncryptedSharedPreferences)
- Валидация API ключа (32+ символов, A-Z, a-z, 0-9)
- Левое drawer-меню с диалогами
- Тёмная/светлая тема
✅ UI/UX
- Material Design 3
- Русский язык интерфейса
- Отступы в поле ввода (12dp)
- Прокрутка к новым сообщениям
- Долгий тап на сообщение - меню Копировать/Редактировать/Удалить
✅ Security
- API ключ: EncryptedSharedPreferences (AES-256-GCM)
- Ключ БД: EncryptedSharedPreferences (AES-256-SIV + AES-256-GCM)
- Профили, сессии, сообщения: SQLCipher
Current Issues & Architecture
⚠️ Важное: Назначение web_search
web_search НЕ является интерфейсом поисковика или Wikipedia. Это инструмент для AI-агента:
Правильная логика работы (Kai-style):
1. AI получает вопрос пользователя
2. AI решает что нужен поиск → вызывает web_search
3. Выполняются ВСЕ tool_calls параллельно
4. Результаты НЕ показываются пользователю - только отправляются AI
5. AI интерпретирует результаты → выдаёт ОДИН финальный ответ
Проблемы с текущей реализацией:
- ❌ Показываем промежуточные ответы пользователю (каждый tool result = сообщение)
- ❌ AI получает результаты и отвечает после КАЖДОГО tool_calls
- ❌ AI выводит куски данных вместо интерпретации
Требуется исправление:
- ✅ Выполнить ВСЕ tool_calls за один проход (уже делаем)
- ✅ Результаты НЕ показывать пользователю (только AI видит)
- ✅ AI интерпретирует и выдаёт ОДИН ответ
🔍 Web Search (Текущая реализация - БЕСПЛАТНОЕ решение)
Используется: Russian Wikipedia API (бесплатно, без API ключа)
- API:
https://ru.wikipedia.org/w/api.php - Метод:
query/list/search- поиск статей по заголовкам - Ограничение результатов: до 10 статей (параметр
num_results) - Ограничение символов: 4000 символов на ответ
- ПРИМЕЧАНИЕ: Это временное решение! Позже можно добавить платный API для полноценного поиска (новости, погода, актуальная информация)
Логика работы:
- AI вызывает
web_searchс текстовым запросом - Выполняется поиск по Wikipedia API
- Результаты (заголовки + сниппеты) обрезаются до 4000 символов
- Результаты отправляются AI для интерпретации
- AI выдаёт ОДИН финальный ответ пользователю
Tool Loop (MainActivity):
- Максимум итераций: 15
- Timeout на итерацию: 30 секунд
- AI может сделать несколько последовательных поисков если нужно
🌤️ Weather Tool (БЕСПЛАТНОЕ решение)
Используется: Open-Meteo API (полностью бесплатно, без API ключа)
- Geocoding API:
https://geocoding-api.open-meteo.com/v1/search- определение координат города - Weather API:
https://api.open-meteo.com/v1/forecast- текущая погода + прогноз на 7 дней - Параметры: температура, ветер, погодные коды, осадки
Логика работы:
- AI вызывает
get_weatherс названием города - Определяются координаты через Geocoding API
- Запрашивается погода по координатам
- Возвращается текущая погода + прогноз на 7 дней
🔗 OpenUrlTool (Часть Phase 3)
Статус: ✅ Реализовано | Оценка: 1 день
Назначение: Позволяет AI парсить любую веб-страницу по URL.
Гибридная схема (AI сам решает откуда взять URL):
- RSS-ленты новостей (рекомендуется):
- lenta.ru → https://lenta.ru/rss/
- kommersant.ru → https://www.kommersant.ru/rss/news.xml
- Из памяти - AI помнит рабочие URL
- Через web_search - находит URL в интернете
- От пользователя - пользователь может передать URL
Логика работы с новостями:
- Получив запрос о новостях → сначала проверь память пользователя (предпочтения по темам)
- Открой RSS-ленту через open_url (самый эффективный способ)
- Составь сводку с учётом интересов пользователя
- Если источники недоступны → используй web_search
- Проверь память приложения
- Выдай ответ на основе всех доступных источников
Реализация:
- HTTP GET запрос к любому URL
- Возврат ТОЛЬКО текста (удаляются HTML теги)
- Ограничение: 4000 символов
- Таймаут: 10 секунд
- Блокировка опасных URL (javascript:, file:, data:)
📚 Изучено из Kai (open-source AI assistant)
Kai имеет отличную документацию по tools: https://kai9000.com/docs/features/tools/
Ключевые решения из Kai:
-
Execution Flow:
- Все tool calls выполняются параллельно (coroutine async/await)
- TOOL_EXECUTING показывается в UI как "пульсирующий индикатор"
- Результаты НЕ показываются пользователю - только отправляются AI
- AI может вызвать еще tool calls → цикл повторяется
- Когда AI отвечает без tool_calls → финальный текст показан пользователю
-
Safety Guards (важно!):
- Iteration limit: максимум 15 итераций
- Repeated call detection: если одинаковый tool с одинаковыми аргументами вызывается 3 раза подряд → остановка
- Timeout: 30 секунд по умолчанию
- Result truncation: результаты > 8000 символов обрезаются
- Context trimming: между итерациями обрезается история сообщений
-
Web Search в Kai:
- Есть встроенный web_search tool
- Работает (вероятно использует платный API или свой парсинг)
Active Plan (Phases 1-3)
Phase 1: Расширенные профили (Extended Profiles)
Статус: ✅ Завершена | Оценка: 1-2 дня
Добавлено поле systemPrompt в профиль для отправки как role: "system".
| Задача | Статус |
|---|---|
| Profile entity | ✅ Добавлено поле systemPrompt |
| Profile dialog UI | ✅ Добавлен EditText с maxLength=4000 |
| ProfileDao | ✅ CRUD работает |
| MainActivity | ✅ Инжектирует systemPrompt как role: "system" |
| MistralClient | ✅ Использует msg.role |
Phase 2: Система памяти (Memory System)
Статус: ✅ Завершена | Оценка: 2-3 дня
Система запоминания информации с категориями и hitCount.
| Задача | Статус |
|---|---|
| Memory entity | ✅ key, value, category, hitCount, timestamps |
| MemoryDao | ✅ CRUD + getByCategory, incrementHitCount, getPromotionCandidates |
| ChatDatabase | ✅ Добавлен MemoryDao, version=2 |
| MemoryRepository | ✅ buildMemoryContext() для инжекции в prompt |
Memory categories:
- GENERAL — общие факты
- LEARNING — выводы и паттерны
- ERROR — известные ошибки
- PREFERENCE — предпочтения пользователя
Prompt injection:
=== Важная информация ===
[Факты]
- ключ: значение
[Выводы]
- ключ: значение (N использований)
[Предпочтения пользователя]
- ключ: значение
Phase 3: Tools / Tool Execution
Статус: ✅ Завершена (тестирование) | Оценка: 3-4 дня
Инструменты для AI (function calling) для выполнения действий.
| Задача | Статус |
|---|---|
| Tool abstract class | ✅ name, description, inputSchema, executor |
| GetTimeTool | ✅ get_local_time с timezone |
| GetDateTool | ✅ get_date с timezone |
| WebSearchTool | ✅ Протестировано (только Wikipedia) |
| GetWeatherTool | ✅ Протестировано (Open-Meteo API) |
| NotificationTool | ✅ send_notification |
| MemoryStoreTool | ✅ Протестировано |
| MemoryLearnTool | ✅ Протестировано |
| MemoryForgetTool | ✅ Протестировано |
| MemoryReinforceTool | ✅ Протестировано |
| MemoryPreferenceTool | ✅ Протестировано |
| ToolExecutor | ✅ управление всеми tools, updateSettings() |
| MistralClient | ✅ tools в chat completion, обработка tool_calls |
| Safety | ✅ Max iterations (15), timeout (30s), result truncation (2000 chars) |
| OpenUrlTool (RSS) | ✅ Автоматическое определение и парсинг RSS/Atom |
RSS-ленты (протестировано):
- lenta.ru/rss/ ✅
- kommersant.ru/rss/news.xml ✅
Тестирование Phase 3:
- ✅ web_search (Wikipedia) - работает
- ✅ get_weather (Open-Meteo) - работает
- ✅ Memory tools - работает, изолирована по профилям (протестировано)
Location Settings (в рамках Phase 3):
| Задача | Статус |
|---|---|
| Preferences keys | ✅ KEY_DEFAULT_TIMEZONE, KEY_DEFAULT_CITY |
| dialog_location.xml | ✅ UI для ввода timezone/city |
| showLocationDialog() | ✅ Реализована в MainActivity |
| drawer_menu.xml | ✅ Добавлен item action_location |
| ic_location.xml | ✅ Создан vector drawable |
| ToolExecutor.updateSettings() | ✅ Принимает timezone/city при сохранении |
Defaults:
- Timezone: Asia/Irkutsk
- City: Иркутск
Unconfirmed Phases (Not Approved)
Следующие фазы требуют дополнительного планирования:
Phase 4: Heartbeat
Оценка: 2-3 дня
Автономная периодическая самопроверка:
- WorkManager задача (каждые 30 минут)
- Active hours (8:00-22:00)
- Обработка ответа (молча vs уведомление)
Phase 5: Email (IMAP/SMTP)
Оценка: 4-5 дней
Интеграция с email без OAuth:
- IMAP клиент (чтение писем)
- SMTP клиент (отправка)
- UI настройки ящика (сервер, порт, логин, пароль)
- Email tools для AI
Technical Context
⚠️ ВАЖНО: Сборка APK после каждого изменения
После каждого исправления или добавления функций НЕОБХОДИМО собирать APK!
Пользователь должен иметь возможность сразу протестировать изменения.
# Сборка APK
JAVA_HOME=/opt/homebrew/opt/openjdk@17 ./gradlew assembleDebug
# Путь к APK
app/build/outputs/apk/debug/app-debug.apk
Key Files
app/src/main/java/com/mistral/chat/ui/MainActivity.kt— главная активностьapp/src/main/java/com/mistral/chat/api/MistralClient.kt— API клиентapp/src/main/java/com/mistral/chat/api/ToolExecutor.kt— менеджер toolsapp/src/main/java/com/mistral/chat/data/ChatDatabase.kt— база данныхapp/src/main/java/com/mistral/chat/data/Profile.kt— профильapp/src/main/java/com/mistral/chat/data/Memory.kt— памятьapp/src/main/res/layout/dialog_location.xml— настройки местоположения
Current Issues
- Кнопка STOP не работает (требует streaming mode)
⚠️ ВАЖНЫЕ ПРАВИЛА РАЗРАБОТКИ
Запрет на удаление реализованных функций
НИКОГДА не удаляй уже реализованные функции! Даже если они кажутся неидеальными:
- Если нужно изменить поведение - исправь, а не удаляй
- Если что-то сломалось - почини, а не упрощай удалением
- При удалении функций (даже "неиспользуемых") всегда согласовывай с пользователем
Запрет на хардкодинг переменных
НИКОГДА не хардкодь значения, которые должны быть динамическими!
- Даты, года, время,地名, названия - всё должно подставляться из системы/контекста
- Если что-то не получается реализовать без хардкода - ОБСУДИ с пользователем перед реализацией
- Пример правильного подхода:
{CURRENT_YEAR}→ подставляется черезSimpleDateFormat
Сборка APK после каждого изменения
После каждого исправления или добавления функций ОБЯЗАТЕЛЬНО собирай APK!
- Пользователь должен иметь возможность сразу протестировать изменения
- Команда:
JAVA_HOME=/opt/homebrew/opt/openjdk@17 ./gradlew assembleDebug - Расположение:
app/build/outputs/apk/debug/app-debug.apk
Дублирование сообщений при переключении сессий (BUG FIX)
Проблема: При переходе из второй сессии в первую (или любую другую) сообщения дублировались.
Причина: Асинхронная загрузка сообщений без проверки актуальности sessionId.
Решение в MainActivity.kt:
- Очищаем список СРАЗУ при переключении (до асинхронной загрузки)
- Используем
loadMessagesJobдля отмены предыдущей загрузки сообщений - Проверяем sessionId внутри async загрузки (несколько раз)
- Передаём
expectedSessionIdвaddMessageдля правильного сохранения в БД - Прокрутка к последнему сообщению после загрузки
⚠️ ВАЖНО: Логика прокрутки чата
Правильная реализация:
- К концу сообщения пользователя - прокрутка к концу (scrollToPosition) через 100мс после добавления
- К началу ответа ИИ - прокрутка к НАЧАЛУ (scrollToPositionWithOffset) через 150мс после добавления сообщения ИИ
Техническая реализация:
- В
addMessage(): для сообщений ИИ (!message.isUser) - прокрутка к началу через 150мс - Используй
layoutManager.scrollToPositionWithOffset(position, 0)для прокрутки к началу элемента - Используй
scrollToPosition(position)для прокрутки к концу элемента - Проверяй
!userScrolledAfterSendперед прокруткой к ответу ИИ
Удаление debug логирования
После отладки и подтверждения что баг исправлен - удали все android.util.Log.d("DEBUG", ...) из кода.
Порядок действий при работе с багом
- Проанализируй код и найди причину
- Исправь проблему, а не симптомы
- Не удаляй существующий функционал
- Проверь что исправление не ломает другие сценарии
- Документируй исправление в agents.md
Выводы и предмет для обсуждения
WebSearchTool
- Wikipedia API - работает, но содержит только энциклопедические статьи (нет погоды, новостей)
- DuckDuckGo Instant Answer API - возвращает 0 результатов для большинства запросов (ограничение бесплатного API)
- Вывод: Текущая реализация web_search не может полноценно заменить поисковик
OpenUrlTool (предложено, отложено)
- AI не знает все URL наизусть - нужен либо справочник в system prompt, либо web_search для нахождения URL
- При гибридном подходе: web_search находит URL → open_url парсит страницу
- Проблема: в system prompt не влезет список URL для всех типичных запросов (погода, новости, курсы валют и т.д.)
- Вывод: Реализация отложена до починки web_search
Tool Execution Loop
- Предыдущая реализация: 1 итерация → результаты → финальный запрос без tools
- Проблема: Не даёт AI сделать несколько последовательных поисков (web_search → получить URL → open_url)
- Новая реализация: до 15 итераций, как в Kai - AI сам решает сколько поисков нужно
- Лимит iteration: 15
- Timeout на итерацию: 30 сек
- Если API Mistral не выдержит - снизим до 10 или 5
📋 Контекст сессии и оптимизация (В ОБСУЖДЕНИИ)
Текущая реализация (без оптимизации)
При каждом запросе отправляется полный контекст:
- System prompt (профиль)
- Текущая дата и время
- Часовой пояс + город
- Контекст профиля (имя, о себе)
- Контекст памяти (факты, выводы, предпочтения)
- ВСЕ сообщения сессии
- Результаты tool calls (полностью, до 2000 символов каждый)
Проблемы:
- При 2-3 tool calls (RSS + статья) добавляется 4000-6000 символов в контекст
- При росте сессии (100+ сообщений) запрос станет слишком большим
- 503 ошибки чаще происходят при больших запросах
- Превышение лимита токенов контекста
Варианты решения
1. Trimming (простое)
- Оставлять только последние N сообщений + память + system prompt
- Просто реализовать, но теряется история
2. Свёртывание tool results
- Не добавлять полный результат open_url в историю
- Добавлять краткую выжимку: "Найдено 5 новостей о [тема]"
- Сложнее реализовать, сохраняет суть
3. Контекстное окно (гибкое)
- Оставлять последние N сообщений + summary предыдущих
- ИИ сам решает что важно
- Сложная реализация
Статус: Не решено, требует обсуждения с пользователем
Conversation Context (for AI Agent)
При начале новой сессии: Прочитай файл AGENTS.md для понимания текущего контекста разработки.
При запросе "продолжаем": Мы работаем над Phase 3 (Tools). Последняя завершённая задача — добавление настроек location (timezone/city) в drawer menu.
Важно:
- Пушить в GitHub только после тестирования и подтверждения пользователя
- Не делать push автоматически после каждого изменения
Last updated: 2026-04-10 Version: 1.9