Skip to content
boomyjeePublic

About

AI agent with different types of memory - file, rag based, letta-like, simple mem, tree-file like and so on

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

slonagent

Непрерывный AI-агент с многослойной долгосрочной памятью, веб-интерфейсом и self-tooling. Telegram + Web dashboard. Работает с Claude, Codex и любым OpenAI-совместимым провайдером.

Desktop — Editor + Chat

Chat Editor Git Files

Ключевое отличие от классических агентов (Claude Code, Codex, OpenCode) — у slonagent нет сессий. Observations автоматически сжимают опыт, контекст освобождается, и агент работает непрерывно — один бесконечный поток разработки без потери контекста.

Как использовать: написать боту в Telegram, открыть веб-дашборд, или добавить бота в группу с топиками.


Архитектура памяти

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

LogCompressor — Mastra Observational Memory

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

LogCompressor — реализация Mastra Observational Memory с теми же промптами, адаптированная для работы через OpenAI-совместимый API.

Работает в два этапа:

Observer смотрит на диалог и превращает его в структурированные наблюдения с приоритетами и временны́ми метками:

Date: Mar 15, 2026 (2 days ago)
* 🔴 (14:30) User stated prefers short answers without lengthy explanations
* 🔴 (14:31) User shared screenplay «Title» (dark comedy, holiday setting):
  * -> Characters: Anna, her ex Mark (arrives unexpectedly)
  * -> Cliffhanger: ambiguous final message implies Mark may not be gone
* 🟡 (14:32) Agent browsed source files for auth flow
  * -> viewed auth.ts — found missing null check

Reflector включается когда наблюдений становится слишком много — переписывает их плотнее, сохраняя суть. Алгоритм адаптивный: если рефлексия получается не меньше оригинала, давление сжатия нарастает до трёх уровней.

Почему это лучше альтернатив:

  • Скользящее окно (WindowCompressor) — просто выбрасывает старое. Агент забывает что было неделю назад.
  • Summarize и забыть — теряет конкретные факты, остаются только обобщения.
  • Mastra: диалог превращается в плотные датированные наблюдения. Агент через месяц знает что сказал пользователь 15 марта в 14:30. Утверждения пользователя — авторитетный источник, а не просто "что-то было сказано".

FactProvider — локальный GraphRAG

Наблюдения из Mastra хранят что происходило. FactProvider хранит что известно — факты об именах, людях, событиях, документах, проектах.

В основе — алгоритмы Hindsight (vectorize.io, 91.4% на LongMemEval), реализованные локально: промпты и логика поиска 1:1, но без внешнего сервера — всё встроено в процесс агента.

Как работает сохранение:

Диалог режется на куски, LLM извлекает из каждого семантически полные факты — не фразы, а утверждения с контекстом:

Анна работает UX-дизайнером в Яндексе с 2021 года
Пользователь переехал в Петербург в марте 2025
Проект "Альфа" отложен из-за смены приоритетов на Q3

Затем сущности связываются и очищаются от дублей: Аня, Anna, Анна Смирнова схлопываются в один узел. Каждый факт привязывается к сущностям, которые в нём участвуют.

Следующий шаг — синтез: все факты об одной сущности собираются вместе и LLM пишет по ним связное наблюдение. Это GraphRAG-подход: не хранить сырые факты, а держать осмысленный актуальный портрет каждой сущности.

Пайплайн recall:

При запросе параллельно ищется по трём слоям: синтезированные наблюдения по сущностям, сырые факты из разговоров и факты из загруженных документов. Внутри каждого слоя — 4-way поиск, объединяемый через RRF:

Метод Что делает
Semantic векторный поиск в LanceDB (cosine similarity)
BM25 полнотекстовый поиск через SQLite FTS5
Graph / LinkExpansion если семантика нашла факт об Анне, граф добавляет все остальные факты о той же Анне — не потому что похожи по тексту, а потому что связаны через общую сущность; плюс причинно-следственные связи между фактами и расширение по связным observations
Temporal dateparser парсит временны́е выражения в запросе → SQL-поиск по диапазону дат + BFS-spreading по temporal/causal ссылкам

RRF объединяет ранги всех четырёх методов в единый список кандидатов. Топ-30 кандидатов уходят в cross-encoder reranker (multilingual MiniLM) — он получает пару (запрос, факт) и выдаёт точный скор релевантности, не зависящий от векторного сходства. После реранкинга применяется бюджет токенов.

Агент получает не просто ближайших соседей по вектору, а факты прошедшие семантику, полный текст, граф связей и временно́й контекст одновременно.

Почему это лучше чистого RAG:

  • Чистый RAG: "найди похожие чанки". Работает если вопрос почти совпадает с текстом.
  • FactProvider: факты → граф сущностей → синтез → тройной поиск + reranking. Работает на семантически далёких запросах и многоуровневых вопросах.

PersonalityProvider — субличности

Хранит не факты, а контексты — именованные грани агента. Каждая субличность — Markdown-файл с описанием и содержимым.

memory/personality/
  common.md        ← общие факты, всегда активна
  slon_dev.md      ← режим разработчика
  screenwriter.md  ← режим сценариста
  archivist.md     ← режим архивариуса

Активные субличности всегда попадают в системный промпт целиком. Агент сам решает какие активировать через personality_load — и сам же обновляет их содержимое через personality_update когда появляется что-то важное.

Это не просто "факты о пользователе" — это то, как агент думает в данном контексте: что знает, что важно, на что обращать внимание.


Итог: почему три слоя лучше одного

Что нужно помнить Кто отвечает
Что говорилось в диалоге, когда, с каким приоритетом LogCompressor (Mastra)
Факты о людях, проектах, событиях, документах FactProvider (Hindsight + GraphRAG)
Как агент должен думать в данном контексте PersonalityProvider

Mastra Observational Memory набирает 94.87% на LongMemEval — SOTA среди систем памяти для агентов. Hindsight — 91.4%, первая система перевалившая за 90% на этом бенчмарке. Здесь оба подхода работают одновременно: Mastra сжимает историю диалога, Hindsight хранит факты и сущности.

Каждый слой независим: компрессор и провайдеры ортогональны, подключаются через конфиг.


Веб-интерфейс

Dashboard — не просто мониторинг, а полноценная IDE-подобная среда для взаимодействия с агентом.

Chat — основной чат с агентом: текст, голос, файлы, изображения. Поддержка markdown, syntax highlighting, inline diff. Работает с мобильных устройств.

Editor — файловый редактор с деревом файлов, Monaco editor (тот же движок что в VS Code), git-интеграцией (diff, commit, history). Агент и пользователь работают с одними файлами.

Logs — Agent, Memory, Transport, Recall — реалтайм логи всех слоёв системы.

Web — встроенный браузер для просмотра CGI-приложений, которые агент создаёт сам (см. Self-tooling ниже).

Настройки — 4 встроенные темы + генеративная тема из 1-2 пользовательских цветов (primary + accent). Цветовая схема всех CSS-переменных генерируется автоматически по HSL, включая синтаксис.

Dashboard доступен локально (http://localhost:8765) и через SSH-туннель по HTTPS для удалённого доступа. Авторизация через cookie.


Self-tooling: агент пишет себе инструменты

Ключевая архитектурная концепция — агент может расширять свои возможности, создавая скрипты, которые сразу становятся доступны по URL.

Как это работает:

  1. Агент пишет Python-скрипт в /workspace/web/ внутри sandbox
  2. Скрипт мгновенно доступен как URL: https://host/agent/dashboard/~/workspace/web/app.py
  3. .py файлы исполняются как CGI — доступны request (method/path/query/headers/body), header() для ответа, print() для body
  4. Статические файлы (HTML/JS/CSS) отдаются как есть
  5. Webhook https://host/agent/dashboard/web-hook — POST-запрос приходит агенту как сообщение

Пример: агент получает задачу "сделай фотодневник". Он пишет diary.py — CGI-скрипт, который сканирует папку с фото, генерирует thumbnails, отдаёт HTML с галереей и lightbox. Пользователь открывает URL в браузере или во вкладке Web дашборда — готовое интерактивное приложение.

Что это даёт:

  • Агент создаёт интерактивные инструменты для задач, которые не ложатся в чат-формат
  • Скрипты персистентны — работают после перезапуска
  • Sandbox изолирует исполнение — скрипт не имеет доступа к хосту
  • Через прокси доступны локальные серверы из sandbox: https://host/agent/dashboard/sandbox/PORT/ — HTTP и WebSocket проксируются автоматически

Это не просто "выполнение кода" — это возможность агента писать себе произвольные веб-приложения как инструменты для решения задач.


Модель безопасности: выполнение кода

Код выполняется в Podman-контейнере (python:3.11-slim), изолированно от хоста. Контейнер персистентный — установленные пакеты и файлы в /workspace сохраняются между вызовами.

По умолчанию контейнер видит только /workspace. Папки хоста подключаются по явному решению пользователя — на чтение или на запись:

/config write sandbox.ro[] C:\Users\me\Downloads
/config write sandbox.rw[] D:\projects\my-app

После этого папки появляются как /mnt/ro/c/users/me/downloads и /mnt/rw/d/projects/my-app. Когда список меняется, контейнер коммитится в образ и пересоздаётся — пакеты не теряются.

Python-скрипты в /workspace/tools/ автоматически становятся инструментами — агент создаёт переиспользуемые утилиты прямо в диалоге, без одобрения, в изоляции контейнера.

При этом sandbox-скиллы не слепы — через RPC-мост им доступен агент: transport.send_message, transport.send_thinking, spawn_subagent, next_message. Этого достаточно для кастомных циклов с UI-обратной связью — скрипт может отправить сообщение пользователю, дождаться ответа и продолжить работу. Всё это работает изолированно в контейнере, без доступа к хост-машине.


Скиллы

Скилл Что делает
SandboxSkill Работа с кодом в Podman-контейнере: exec, read, edit, write, grep, glob
CodingSkill Системный промпт и воркфлоу для кодинг-режима в sandbox
WebSkill Поиск в интернете (Brave Search) и скачивание веб-страниц
NanoBananaSkill Генерация и редактирование изображений через Gemini Imagen
CronSkill Планировщик: одноразовые и повторяющиеся задачи (hourly/daily/weekly)
McpSkill Подключение произвольных MCP-серверов и проброс их инструментов агенту
ConfigSkill Чтение и запись конфига агента через /config

Саморасширение

Скиллы и песочница вместе дают агенту возможность расширять собственные способности — без участия разработчика.

Кастомные лупы

Стандартный цикл агента — llm() → tool_calls → dispatch → llm() → ... — универсален, но не оптимален для сложных задач. Человек-разработчик решает это написанием специализированного pipeline с шагами, валидацией и retry.

Агент может сделать то же самое: написать себе скилл в sandbox с кастомным циклом — например, пошаговая генерация с проверкой каждого шага, или итеративное улучшение с оценкой качества. Скилл сохраняется в /workspace/tools/ и сразу становится постоянным инструментом. В следующий раз агент вызывает свой pipeline как обычный tool. Через RPC-мост скилл имеет доступ к transport и субагентам — может общаться с пользователем и координировать работу.

Веб-приложения через CGI

Иногда чат — не тот интерфейс для задачи. Фотодневник, шахматная партия, работа с видео — всё это требует структурированного UI.

Агент может написать CGI-скрипт или полноценное веб-приложение в sandbox — оно мгновенно доступно по URL через dashboard proxy (см. Self-tooling выше). Это не требует отдельного деплоя или настройки сервера — написал файл, открыл URL.

Ключевое: все три механизма расширения работают через одну систему. Кастомный луп — skill в /workspace/tools/. Веб-приложение — скрипт в /workspace/web/. Оба исполняются в sandbox. Агент не выходит за рамки архитектуры — он использует её для роста.


Форк-агенты

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

При первом сообщении в новом топике бот спрашивает как создать агента:

  • Чистый агент — начинает с нуля, без памяти
  • Клон с памятью — копирует субличности и память об инструментах из основного агента

Форк-агент использует облегчённую конфигурацию из секции fork_agent в конфиге — по умолчанию более быстрая модель и только провайдеры памяти, которые имеет смысл разделять (personality, tool). Все остальные параметры наследуются от agent.

Данные форк-агентов хранятся в forks/<agent_id>/ — имя задаётся при создании.


Треды

Внутри каждого агента (основного или форка) может быть несколько тредов — независимых потоков диалога с общей памятью.

Каждый тред — это отдельный поток диалога (CONTEXT_{uuid}.json) со своей историей сообщений. Системный промпт (субличности), факты и observations общие для всех тредов агента — но observations помечены идентификатором треда, так что агент знает, в каком треде что произошло.

memory/
  CONTEXT.json            ← главный тред (uuid = "")
  CONTEXT_c84b0ee8.json   ← второй тред
  THREADS.json            ← реестр: uuid → имя
  fact/                   ← общая для всех тредов
  personality/            ← общая для всех тредов

В веб-интерфейсе треды переключаются через вкладки. В Telegram — через топики группы.


Установка

Требования:

  • Python 3.12 (3.13+ несовместим с некоторыми бинарными зависимостями — pandas, lancedb)
  • Podman — для SandboxSkill. Должен быть доступен в PATH.
git clone https://github.com/boomyjee/slonagent.git
cd slonagent
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt

Конфигурация

Скопируй .config.sample.json в .config.json и замени на свои значения:

{
    "env": {
        "HTTPS_PROXY": "http://user:pass@host:port",
        "HF_HUB_OFFLINE": "0"
    },
    "keys": {
        "llm": "YOUR_LLM_API_KEY",
        "llm_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
        "gemini": "YOUR_GEMINI_API_KEY",
        "brave": "YOUR_BRAVE_API_KEY"
    },
    "telegram": {
        "bot_token": "YOUR_BOT_TOKEN",
        "allowed_user_ids": [123456789],
        "transport": { "verbose": false }
    }
}

env — переменные окружения, задаются до старта (прокси, HuggingFace offline-режим и т.д.). llm / llm_url — ключ и базовый URL для LLM (любой OpenAI-совместимый провайдер). gemini — нативный ключ Gemini API, нужен только для NanoBananaSkill (генерация изображений). Синтаксис $keys.llm в других секциях — ссылка на значение из этого же конфига. Полный пример со всеми секциями — в .config.sample.json.

Параметры LogCompressor

Параметр Default Описание
compress_after_tokens 30000 при каком объёме истории запускается Observer
recent_tokens 8000 сколько свежей истории оставлять несжатой
reflect_after_tokens 40000 при каком объёме наблюдений запускается Reflector

Параметры FactProvider

Параметр Default Описание
auto_recall false автоматически подмешивать recall в системный промпт (агент вызывает fact_recall сам)
auto_consolidate true запускать синтез observations после retain
embedding_model Qwen3-Embedding-0.6B (локально) модель эмбеддингов; при provider: google — Gemini Embedding API

Запуск

# Telegram
start.bat

# CLI
start.bat --cli

Веб-дашборд доступен по адресу http://localhost:8765 сразу после запуска.


Структура данных

memory/
  CONTEXT.json            ← главный тред: история + compressed observations
  CONTEXT_{uuid}.json     ← дополнительные треды
  THREADS.json            ← реестр тредов: uuid → имя
  CRON.json               ← задачи планировщика
  LOG.md                  ← debug-дамп наблюдений (только для чтения)
  fact/
    facts.db              ← SQLite: факты, сущности, observations (общие для тредов)
    lancedb/              ← векторный индекс
  personality/            ← субличности (.md файлы, общие для тредов)
  workspace/              ← рабочая директория агента (файлы, артефакты)
forks/
  <agent_id>/             ← форк-агент со своей memory/ и .config.json

About

AI agent with different types of memory - file, rag based, letta-like, simple mem, tree-file like and so on

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages