Обновления продукта

Что нового в AIPi

Мы регулярно выпускаем обновления: новые возможности, улучшения и исправления. Здесь — история изменений в обратном порядке, от свежих релизов к первым.

Текущая версия v1.1.1

v1.1.1

Текущая
Новое
  • Все агенты DeepSeek переведены на актуальную модель deepseek-flash (миграция 017)

    Все агенты на DeepSeek — то есть все субагенты, кроме codexbase (Codex CLI), и сам оркестратор — теперь работают на самой свежей модели DeepSeek. Актуальный идентификатор — deepseek-flash (DeepSeek-V4.1-Flash, выпущена 10.09.2026); идентификаторы deepseek-v4-flash и deepseek-v4-pro — предыдущее поколение и снятые с поддержки алиасы: провайдер их ещё принимает, но текущей моделью они больше не являются.

    Причина дефекта: снятый с поддержки алиас deepseek-v4-flash стоял в каталоге первым и поэтому молча становился моделью по умолчанию для всех агентов DeepSeek.

    Код
    - src/ai/model-registry.ts: записи каталога теперь можно помечать признаком legacy: true, и defaultModelFor() их пропускает — устаревшая модель больше никогда не станет значением по умолчанию. Сами устаревшие идентификаторы продолжают полноценно разрешаться (поиск в каталоге, распознавание изображений, тарифы, явный выбор), защищены только значения по умолчанию. Добавлена общая константа DEFAULT_DEEPSEEK_MODEL, вычисляемая из каталога.
    - src/agent/tools/handlers/agent-tools.ts: два зашитых запасных значения || 'deepseek-v4-flash' заменены на DEFAULT_DEEPSEEK_MODEL.
    - src/agent/task-summary-generator.ts, src/agent/task-name-generator.ts: значения по умолчанию вспомогательных генераторов тоже переведены на общую константу.
    - src/ai/pricing.ts, web/src/components/chat/modelMeta.tsx: исправлены устаревшие комментарии, утверждавшие, что v4-pro маршрутизируется и тарифицируется как Flash. DeepSeek отозвал эту схему 11.09.2026, у v4-pro свой тариф. Цифры тарифов и бейджи моделей не менялись.

    Миграция
    - migrations/017_run_deepseek_agents_on_current_model.sql перенаправляет уже сохранённые данные: subagents.model_override (все слаги, кроме codexbase), app_settings.{defaultModel,modelMedium,modelHigh,modelUltra}, projects.{orchestrator_model,subagent_model}, project_tasks.orchestrator_model и четыре колонки моделей в organization_settings. Каждый запрос защищён условием на старое значение, поэтому повторный запуск не затрагивает ни одной строки. Никаких DROP, TRUNCATE и DELETE; отсутствующие таблицы и колонки пропускаются. Миграция не трогает disabled_models, ui.show_model и subagent_fallback_mode. Те же изменения были применены вручную на dev, тестовом и боевом стендах 08.10.2026 — этот файл их закрепляет, чтобы восстановление из резервной копии или новый стенд приходили в то же состояние.

    Тесты
    - tests/model-registry-deepseek-default.test.ts фиксирует выбор модели по умолчанию (обе роли → deepseek-flash), признаки устаревших записей, обратную совместимость алиасов и неизменные значения по умолчанию у остальных провайдеров.
    - tests/migration-017.test.ts фиксирует имя файла миграции, её идемпотентность, безопасность и точный набор обновляемых записей.

  • Ротация JSONL-логов задач (хранение 30 дней)

    Пофайловые JSONL-логи задач бота (/opt/aipi-agent/logs/tasks/*.jsonl) не очищались и росли бесконечно. Добавлен хостовый cron-скрипт, который удаляет файлы старше 30 дней (параметр TASK_LOGS_MAX_AGE_DAYS) и убирает пустые каталоги организаций.

  • Данные журнальных и диагностических таблиц исключены из дампа

    Одна только таблица api_calls занимала 977 МБ (из них 804 МБ — request_messages: полный контекст каждого вызова, включая base64-картинки из результатов инструментов). Дамп — не место для архивации такого журнала.

    Из дампа исключены ДАННЫЕ (схема сохраняется, поэтому при восстановлении таблицы создаются пустыми и приложение продолжает в них писать) для таблиц: api_calls, server_metric_samples, proxy_metric_samples, admin_audit_log, audit_log, command_logs, sdk_usage_logs, diagnostics, prompt_history.

    Переопределяется переменной AIPI_EXCLUDE_DATA_TABLES.

  • Набор фавиконов для каждого инстанса через AIPI_ICON_VARIANT
    • В репозиторий добавлены три готовых набора фавиконов (teal/red/green, по 12 файлов) в web/favicons/<variant>/.
    • Добавлен плагин Vite (web/vite.config.ts), который кладёт выбранный набор в корень web/dist, чтобы express.static отдавал /favicon.svg, /favicon.ico, /apple-touch-icon.png, /manifest.json, /icon-*.png. Набор берётся из AIPI_ICON_VARIANT (по умолчанию teal); неизвестный, пустой или отсутствующий набор валит сборку.
    • AIPI_ICON_VARIANT проброшен через frontend-стадию Dockerfile (ARG по умолчанию teal + ENV) и build-args bot/worker/pool-manager в docker-compose.yml (${AIPI_ICON_VARIANT:-teal}).

    Существующие строки подключения иконок, манифеста и theme-color в HTML не менялись.

  • Настраиваемый текст бейджа dev-инстанса (VITE_DEV_BADGE_TEXT)

    Текст красной плашки в правом нижнем углу на тестовом и разработочном стендах теперь задаётся переменной VITE_DEV_BADGE_TEXT (по умолчанию «ТЕСТ»), поэтому каждый стенд подписывается по-своему.

  • Настраиваемый PRIVATE_BIND_IP и флаг VITE_DEV_INSTANCE
    • docker-compose.yml: привязка приватных портов db/redis/redis-transport заменена на ${PRIVATE_BIND_IP:-192.168.0.149}; значение по умолчанию сохраняет прежнее поведение на боевом стенде без переменной.
    • Dockerfile и build-args bot/worker/pool-manager: VITE_DEV_INSTANCE пробрасывается в web-бандл на этапе сборки; значения «true»/«1» помечают инстанс как dev независимо от хоста (плашка «ТЕСТ» и dev-тема).
    • web/src/utils/devHost.ts: флаг DEV_INSTANCE_FLAG либо прежняя проверка по хосту.
    • .env.example: задокументированы PRIVATE_BIND_IP и VITE_DEV_INSTANCE.
  • Фавикон AIPi (значок с двумя точками)

    Обновлён фавикон AIPi — значок с двумя точками.

  • Блокировка песочниц на отдельном сервере (sandbox_blocked)

    Основной сервер приложения не должен размещать у себя песочницы, и делать песочницы избыточными за счёт кластеризации не планируется — они остаются обычными серверами. Поэтому главному хосту нужен способ выводиться из размещения песочниц и проектов после того, как система его разгрузит: без перевода в состояние «frozen» (оно означает «на выход» и делает сервер удаляемым) и не затрагивая проекты, которые он уже обслуживает.

    Флаг политики — servers.sandbox_blocked (миграция 005). Заблокированный сервер:

    • никогда не выбирается целью размещения для НОВОГО проекта (pickBestServer), а значит, на нём не появляются новые песочницы — песочница живёт на сервере своего проекта;
    • никогда не выбирается целью для переноса, поэтому проекты с других серверов на него не переезжают;
    • не получает новых воркеров (ни автоматически, ни вручную) и пропускается прогревом;
    • обнуляет число воркеров в 60-секундном проходе пула, но ТОЛЬКО когда на нём не осталось привязанных проектов: снятие воркеров у сервера, который ещё владеет проектами, их сломало бы. Пул никогда не опустошается: если другого пригодного сервера нет, блокировка остаётся в ожидании.

    Проекты, уже привязанные к заблокированному серверу, продолжают работать; флаг не зависит от «frozen» и от права на удаление.

    Выбор места размещения теперь идёт через одно общее условие canAcceptNewPlacement, поэтому очередь, выбор цели для переноса и масштабирование не могут разойтись.

  • Выгрузка резервных копий БД и Redis во внешнее хранилище S3
    • scripts/s3-upload.py (новый): помощник на boto3, загружает файл в бакет резервных копий. Учётные данные читаются из /etc/aipi/s3-backup.env (доступен только root, в git не попадает). Перезапись идемпотентна.
    • scripts/aipi-backup-db.sh: после проверенного локального дампа — выгрузка в S3 в каталог db-backups/ (локальная копия остаётся основной, S3 — внешняя копия на случай потери сервера).
    • scripts/aipi-backup-redis.sh (новый): BGSAVE → копирование RDB из контейнера → выгрузка в S3 в каталог redis-backups/. Транспортный инстанс необязателен (данные с TTL, самовосстанавливающиеся) и по умолчанию выключен.
  • Пул чтения с реплики (READ_DATABASE_URL)

    По умолчанию безопасно: без READ_DATABASE_URL ничего не меняется — чтение идёт с основного сервера. Когда управляемая реплика будет готова, установка READ_DATABASE_URL даёт отдельный пул для чтения, чтобы увести тяжёлые SELECT-запросы с основного сервера.

    • config.ts: добавлены db.readUrl (READ_DATABASE_URL) и Config.readDatabaseUrl.
    • pool.ts: выделена wrapPool(); добавлена createReadDbPool() (меньший пул с той же обёрткой set_config по организации, поэтому чтение с реплики остаётся в границах организации).
    • .env.example: задокументирована READ_DATABASE_URL.