Skip to content

Імпорт та експорт агента

Як агент переїжджає між текою .agent/ окремого рантайму і Postgres Agentfy.ai — в обидва боки. Це адаптер agent/package; той самий код обслуговує materialize/sync воркера. Див. також Сумісність з .agent.

Імпорт — .agent/ → Agentfy.ai DB

importAgent(dir, { teamId, agentId? }). Runtime-агент одно-тенантний, Agentfy.ai — мультитенантний, тому імпорту потрібен цільовий teamId (і опц. agentId для оновлення). Усе — ідемпотентний upsert за натуральними ключами, по секціях у транзакції.

Порядок (батьки раніше)

team (дано) → agent → { skill, memory, secret, access } → chat

Що куди

КрокДжерело (.agent/)→ Agentfy.aiЯк
1SOUL.mdagent.soulзберегти тіло дослівно (те саме ім'я, без перейменування)
1agent.config.jsonagent.config (дослівно)зберігається як є; runtimeProfile / ліміти / accessStrategy читаються з нього (runtimeProfile дефолтиться, якщо немає)
1USER.md, HEARTBEAT.mdagent.user, agent.heartbeatзберегти дослівно (інтервал heartbeat береться з config)
2skills/<n>/SKILL.mdрядки skill (+ ассети → system/file)парс frontmatter + тіло
3MEMORY.md, memory/*.mdmemory (curated + daily[date])той самий текст; daily за ключем agentId+date
3data/memory.sqliteперебудовується, не імпортується (re-embed з markdown)
4data/secrets/<uid>.jsonsecret (лише іменаpendingKeys)AGNT2-74: пакет несе ІМЕНА ключів, ніколи значення; значення зі старого файлу відкидаються, лишаються тільки імена
5data/access.json + accessStrategyaccess (ACL + стратегія)channel-user-id → user Agentfy.ai
6data/sessions/<chan>:<uid>.jsonlchat (тред + повідомлення)події → повідомлення в порядку ts
7data/usage.jsonsystem/usage (опц. baseline)зазвичай пропускаємо (forward-looking)
7browser-state/*.jsonapp/account (опц.)чутливе/ефемерне; часто пропускаємо

Маппінг подій сесії → chat

Кожен рядок JSONL { id, type, ts, data }:

type події
usermessage(role=user, text, from)
assistantmessage(role=assistant, text)
tool_callзапис виклику (name, params, toolUseId)
tool_resultрезультат (toolUseId, result)
summaryмаркер компакта/саммарі

Оригінальний event.id зберігається як externalId → повторний імпорт ідемпотентний (без дублів).

Наскрізні правила трансформації

  • ID: runtime-UUID → externalId; Agentfy.ai генерить свій {slice}-uuid.
  • Час: epoch ms → DateTime.
  • Секрети: лише імена (AGNT2-74). Пакет ніколи не несе значення креда, тому імпорт оголошує імена (AgentSecret.pendingKeys), а значення вводяться руками на місці призначення. Доки цього не зроблено, діалог імпорту та екран секретів називають відсутні.
  • Похідні індекси (memory.sqlite, OpenSearch, pgvector) не переносяться — перебудовуються з канонічного markdown/json/jsonl.

Експорт — Agentfy.ai DB → .agent/

exportAgent(agentId, { userScope? }) — зворотна проєкція в теку .agent/ (tarball або директорія). Round-trip працює, бо обидві сторони говорять одним форматом пакета.

Джерело (Agentfy.ai).agent/
agent.soulSOUL.md (тіло як є)
agent.config (дослівно)agent.config.json
agent.user · agent.heartbeatUSER.md · HEARTBEAT.md
memory curated · dailyMEMORY.md · memory/YYYY-MM-DD.md
skill (+ ассети)skills/<name>/SKILL.md
secret (лише імена, без розшифрування)data/secrets/{shared|agent|user-<userId>}.json
accessdata/access.json
chat threads → подіїdata/sessions/<chan>:<user>.jsonl
system/usage (опц.)data/usage.json
куки app/accountbrowser-state/<profile>.json
  • data/memory.sqlite не пишемо — рантайм перебудує FTS з markdown на старті.
  • Результат можна pull-нути рантаймом (через S3) або запустити напряму — агент «переїхав».

Межі та за що пакет відхиляється

Імпорт матеріалізує весь архів у пам'яті до того, як з нього щось прочитано, тому стеля — це властивість завантаження, а не агента, який у ньому описаний:

завантаження25 МБ
записів20 000, включно з каталогами
сумарно в розпакованому вигляді128 МБ — перевіряється двічі: проти того, що оголошує директорія (до розпакування бодай одного байта), і проти того, що розпакувальник справді виробляє
стисненнялише STORE і DEFLATE. bzip2/lzma відхиляються як непідтриманий метод, і це інше повідомлення, ніж «це не zip»

У кожної відмови є код, а не фраза. Причина їде у відповіді про помилку полем details.refusal, а застосунок тримає по одному тексту на код. Причина, додана на сервері, не може мовчки впасти в загальний хвіст — код без тексту червонить тест.

Імпорт — усе або нічого. Відхилений імпорт лишає нуль рядків: напівзібраного агента в списку не буде. Значення, яких не тримає база — байт NUL, непарний сурогат, відмітка часу поза діапазоном timestamptz, — відхиляються на межі з назвою поля, а не доїжджають до Postgres і повертаються п'ятисоткою. (NUL — не ворожий ввід: ditto на теці в macOS кладе в архів сайдкари AppleDouble.)

Ніщо в пакеті не може назвати шлях за межами .agent/ — у жодну зі сторін. Запис, який ліг би поза текою, відхиляється на імпорті; і жодне значення з пакета — userId, ім'я навички, дата пам'яті — не може вивести ім'я запису назовні на експорті.

Типу агента в маніфесті немає (див. Склад). concierge не можна ні експортувати, ні перезаписати завантаженням; закриті обидві сторони, бо імпортер знаходить наявного агента за externalId.

Пакет приїжджає завантаженням або зі сховища, прив'язаного до орендаря, — але ніколи шляхом на сервері. Джерела «прочитай ось цей каталог» у HTTP-контракті немає: шлях від викликача дозволив би будь-якому автентифікованому учаснику змусити сервер обійти й вичитати будь-який каталог, до якого дотягується процес.

Архів пишеться так, щоб його читали чужі розпакувальники і щоб він був стабільним. Імена записів несуть UNIX-маркер платформи, тому не-ASCII ім'я навички розпаковується штатними засобами macOS і Linux вірно, а не сміттям; відмітки часу записів фіксовані, тому два експорти незмінного агента — ті самі байти.

Ідемпотентність ключується парою (teamId, externalId). Той самий пакет, імпортований двічі в одну команду, оновлює того самого агента; імпортований у дві різні команди дає двох незалежних агентів, у яких просто спільний origin id.

Round-trip

  • Чисто round-trip: SOUL / agent.config / MEMORY / skills / access (текст + JSON) та імена секретів разом зі scope.
  • Значення секретів — навмисний виняток (AGNT2-74): вони ніколи не потрапляють у пакет, тому переїзд завжди закінчується словами «введіть ці N кредів».
  • Sessions: без втрат, якщо маппінг типів подій повний (user/assistant/tool_call/tool_result/summary).
  • Індекси: похідні всюди → регенеруються з кожного боку, у пакеті не передаються.

Де запускається

  • CLI / admin-ендпоінт: agentfy import ./.agent --team <teamId> · agentfy export <agentId> -o ./out.
  • Воркер (той самий адаптер): materialize = export (hydrate .agent/ на поді перед турном); delta-sync = import (синк дельт після турна). Перевикористовує diff/S3-синк рантайму.
  • Код: api → адаптер agent/package.