Совместимость с .agent рантайма
Отдельный CleanSlice runtime (cleanslice/runtime) хранит агента как портативную папку .agent/ (SOUL, MEMORY, skills, sessions, secrets, config…). Agentfy.ai 2.0 должен быть совместим с этим форматом, чтобы: импортировать существующих runtime-агентов, запускать цикл агента рантайма без изменений в нашем worker, и экспортировать/бэкапить агента для портативности.
Раскладка .agent/
.agent/
├── SOUL.md # персона / системный промпт (managed-файл)
├── USER.md # пользовательский контекст
├── MEMORY.md # курируемая долгосрочная память
├── HEARTBEAT.md # промпт heartbeat
├── agent.config.json # IAgentConfig: maxIterations, maxTokens, accessStrategy,
│ # heartbeat, session(compaction), memory(limits/review),
│ # stopPhrases, managedFiles, syncSkills, tools{...}
├── memory/ # роллинг дневной памяти (YYYY-MM-DD.md)
├── skills/<name>/SKILL.md # скиллы (markdown + frontmatter)
└── data/
├── access.json # users{ id: {status, inviteCode/accessCode, createdAt} }
├── secrets/<userId>.json # { "service:key": value } (напр. gmail:app_password)
├── sessions/<chan>:<user>.jsonl # лог событий: {id,type,ts,data} построчно
├── memory.sqlite # FTS-индекс по памяти
└── usage.json # потребление токенов
# + browser-state/<profile>.json (живые куки/состояние браузера)Маппинг .agent/ ↔ сущности Agentfy.ai
.agent/ | Agentfy.ai 2.0 (близкая совместимость — те же имена) |
|---|---|
SOUL.md | agent.soul (персона / системный промпт — хранится дословно) |
USER.md | agent.user (контекст человека/профиля — хранится дословно) |
HEARTBEAT.md | agent.heartbeat (промпт heartbeat) |
agent.config.json | agent.config — хранится дословно как IAgentConfig; лимиты / accessStrategy / runtimeProfile читаются из него, а не переименовываются в другие слайсы |
MEMORY.md + memory/*.md | agent/memory (curated = MEMORY.md, daily[date] = memory/YYYY-MM-DD.md — тот же текст) |
data/memory.sqlite | — (FTS-индекс — производный, перестраивается на старте; не хранится/не переносится) |
skills/<name>/SKILL.md | agent/skill (имя + frontmatter + тело дословно) (слайс добавить — см. пробелы) |
data/sessions/<chan>:<uid>.jsonl | chat (события как есть {id,type,ts,data}; id→externalId) |
data/access.json | agent/access (сохраняет форму users{ id:{status,inviteCode/accessCode,createdAt} }) |
data/secrets/<userId>.json | agent/secret (сохраняет карту service:key→value; шифруется at-rest) |
data/usage.json | system/usage (BillingEvent'ы) |
browser-state/*.json | app/account (состояние коннектора) / браузер-сессия воркера |
workspace/ | /workspace воркера (emptyDir) + результаты → system/file |
Близкая совместимость — храним собственные имена рантайма
Мы намеренно сохраняем имена полей рантайма в БД, а не переименовываем их в принятые в CleanSlice. SOUL.md хранится как soul, USER.md — как user, MEMORY.md — как memory, HEARTBEAT.md — как heartbeat, а agent.config.json сохраняется дословно как config. Managed-markdown файлы маппятся 1:1 на колонки с тем же стемом; конфиг-JSON опрашивается на месте (лимиты, accessStrategy, runtimeProfile), а не раскладывается и переименовывается по setting / runtimeProfile / access.
Почему: адаптер становится проекцией, близкой к тождественной, а не семантическим переводом — round-trip без потерь, цикл рантайма читает/пишет те же самые имена, и нет слоя переименований, который мог бы разъехаться. Когда рантайм позже добавит новый managed-файл, он ляжет новым полем с тем же именем без изменения маппинга. (Другие слайсы вроде setting могут зеркалить/читать значения из config для кросс-агентных запросов, но config остаётся источником истины и не переписывается.)
Стратегия: .agent/ — портативный пакет + формат на поде
- Postgres — нормализованный источник истины (строка Agent, память, чат, секреты, доступ…).
.agent/— проекция этого состояния, используется как (a) пакет обмена/бэкапа и (b) рабочая директория на поде, когдаworkerкрутит цикл рантайма.- Двунаправленный адаптер (
agent/package) маппит между ними;workerматериализует.agent/из БД перед турном и синхронит дельты назад после.
Именно это позволяет worker'у переиспользовать цикл + тул-исполнители рантайма без изменений — они читают/пишут .agent/, а адаптер держит БД в синхроне.
Материализация / синхронизация на рантайме
турну нужен рантайм
→ менеджер воркера hydrate'ит .agent/ из Postgres (+ object storage) в workspace пода
→ цикл рантайма работает против .agent/ (без изменений — читает SOUL/MEMORY/skills, пишет sessions/…)
→ по завершении: синхронит дельты назад
sessions/*.jsonl → chat (новые сообщения)
MEMORY.md, memory/*.md → agent/memory
data/secrets/* → agent/secret (если изменились)
data/usage.json → system/usage события
browser-state/* → app/account
→ workspace стирается; долговечный стейт уже сохранёнПереиспользуем существующую diff-manifest S3-синхронизацию рантайма (pull-on-boot / push-on-change): под может тянуть материализованный .agent/ из object storage и пушить изменения, так что слой синхронизации — тот, что рантайм уже поставляет; Agentfy.ai владеет лишь проекцией БД↔пакет.
Импорт / экспорт
- Импорт папки
.agent/→ создать/обновить сущности Agentfy.ai (онбординг существующего runtime-агента). - Экспорт агента → папка
.agent/(бэкап, портативность или запуск на отдельном рантайме). Round-trip работает, потому что обе стороны говорят на одном формате пакета.
Пробелы для полной совместимости
- Добавить
agent/skill(markdown-скиллы с frontmatter) в группуagent— у рантайма есть скиллы; наша L5-разбивка их потеряла. Также подтвердить наличие сабслайсовagent/secret,agent/access,agent/heartbeat,agent/cron(они маппятся 1:1 на.agent/). sessions/*.jsonl↔chat: определить маппинг типов событий (user/assistant/tool_call/tool_result/summary→ строки сообщений + tool/summary-записи).access.json↔user: рантайм ключует пользователей по id канала (напр. Telegram id); смаппить на идентичностиuser/team Agentfy.ai.- Версионирование: запинить версию схемы
.agent(рантайм её развивает) и держать адаптер толерантным к отсутствующим/лишним файлам.
Где живёт
- Адаптер:
api→agent/package(импорт/экспорт + маппинг БД↔.agent/). - Материализатор/синк: слайс
runtime/worker(hydrate перед турном, синк дельт после), переиспользуя S3/diff-синк рантайма. - Цикл + тул-исполнители: приложение
workerберёт их изcleanslice/runtimeи гоняет против материализованной.agent/.