mistral-chat-app/AGENTS.md

24 KiB
Raw Blame History

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 НЕ является интерфейсом поисковика или 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 для полноценного поиска (новости, погода, актуальная информация)

Логика работы:

  1. AI вызывает web_search с текстовым запросом
  2. Выполняется поиск по Wikipedia API
  3. Результаты (заголовки + сниппеты) обрезаются до 4000 символов
  4. Результаты отправляются AI для интерпретации
  5. 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 дней
  • Параметры: температура, ветер, погодные коды, осадки

Логика работы:

  1. AI вызывает get_weather с названием города
  2. Определяются координаты через Geocoding API
  3. Запрашивается погода по координатам
  4. Возвращается текущая погода + прогноз на 7 дней

🔗 OpenUrlTool (Часть Phase 3)

Статус: Реализовано | Оценка: 1 день

Назначение: Позволяет AI парсить любую веб-страницу по URL.

Гибридная схема (AI сам решает откуда взять URL):

  1. RSS-ленты новостей (рекомендуется):
  2. Из памяти - AI помнит рабочие URL
  3. Через web_search - находит URL в интернете
  4. От пользователя - пользователь может передать URL

Логика работы с новостями:

  1. Получив запрос о новостях → сначала проверь память пользователя (предпочтения по темам)
  2. Открой RSS-ленту через open_url (самый эффективный способ)
  3. Составь сводку с учётом интересов пользователя
  4. Если источники недоступны → используй web_search
  5. Проверь память приложения
  6. Выдай ответ на основе всех доступных источников

Реализация:

  • HTTP GET запрос к любому URL
  • Возврат ТОЛЬКО текста (удаляются HTML теги)
  • Ограничение: 4000 символов
  • Таймаут: 10 секунд
  • Блокировка опасных URL (javascript:, file:, data:)

📚 Изучено из Kai (open-source AI assistant)

Kai имеет отличную документацию по tools: https://kai9000.com/docs/features/tools/

Ключевые решения из Kai:

  1. Execution Flow:

    • Все tool calls выполняются параллельно (coroutine async/await)
    • TOOL_EXECUTING показывается в UI как "пульсирующий индикатор"
    • Результаты НЕ показываются пользователю - только отправляются AI
    • AI может вызвать еще tool calls → цикл повторяется
    • Когда AI отвечает без tool_calls → финальный текст показан пользователю
  2. Safety Guards (важно!):

    • Iteration limit: максимум 15 итераций
    • Repeated call detection: если одинаковый tool с одинаковыми аргументами вызывается 3 раза подряд → остановка
    • Timeout: 30 секунд по умолчанию
    • Result truncation: результаты > 8000 символов обрезаются
    • Context trimming: между итерациями обрезается история сообщений
  3. 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 — менеджер tools
  • app/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:

  1. Очищаем список СРАЗУ при переключении (до асинхронной загрузки)
  2. Используем loadMessagesJob для отмены предыдущей загрузки сообщений
  3. Проверяем sessionId внутри async загрузки (несколько раз)
  4. Передаём expectedSessionId в addMessage для правильного сохранения в БД
  5. Прокрутка к последнему сообщению после загрузки

⚠️ ВАЖНО: Логика прокрутки чата

Правильная реализация:

  1. К концу сообщения пользователя - прокрутка к концу (scrollToPosition) через 100мс после добавления
  2. К началу ответа ИИ - прокрутка к НАЧАЛУ (scrollToPositionWithOffset) через 150мс после добавления сообщения ИИ

Техническая реализация:

  • В addMessage(): для сообщений ИИ (!message.isUser) - прокрутка к началу через 150мс
  • Используй layoutManager.scrollToPositionWithOffset(position, 0) для прокрутки к началу элемента
  • Используй scrollToPosition(position) для прокрутки к концу элемента
  • Проверяй !userScrolledAfterSend перед прокруткой к ответу ИИ

Удаление debug логирования

После отладки и подтверждения что баг исправлен - удали все android.util.Log.d("DEBUG", ...) из кода.

Порядок действий при работе с багом

  1. Проанализируй код и найди причину
  2. Исправь проблему, а не симптомы
  3. Не удаляй существующий функционал
  4. Проверь что исправление не ломает другие сценарии
  5. Документируй исправление в 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

📋 Контекст сессии и оптимизация (В ОБСУЖДЕНИИ)

Текущая реализация (без оптимизации)

При каждом запросе отправляется полный контекст:

  1. System prompt (профиль)
  2. Текущая дата и время
  3. Часовой пояс + город
  4. Контекст профиля (имя, о себе)
  5. Контекст памяти (факты, выводы, предпочтения)
  6. ВСЕ сообщения сессии
  7. Результаты 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