Skip to content

Implementation

Build-промпт для AI-кодинг-агента: что именно реализовать для подсистемы Worker, в каком порядке и против каких контрактов. Передай блок ниже агенту; разделы после него — референс, которому он должен следовать.

Эта страница — промпт для агента

У каждого раздела этих доков есть страница Implementation — точная, copy-paste спека задачи, которую агент выполняет. Сначала прочитай Deploy, Use и Destroy; они — источник истины, на который указывает этот промпт.

Промпт

text
ROLE: You are implementing the Worker subsystem of Agentfy.ai 2.0 (NestJS + Prisma + CleanSlice).

GOAL: An agent's "hands" — an on-demand worker (bash / fs / browser) that runs one obligation as an
ephemeral k8s Job, streams progress back to the brain over a WebSocket, persists outputs, and
disappears. The brain (api) keeps the LLM loop; the worker has NO LLM.

DELIVERABLES
1) `worker` app (the worker image): an agent-less, LLM-less **MCP server**.
   - Embeds an MCP server; dials CONTROL_URL over a WebSocket (reverse transport) and runs the MCP
     `initialize` handshake with WORKER_TOKEN, then signals `ready`.
   - Advertises via `tools/list` ONLY the TOOL_ALLOWLIST tools: exec, process_exec, file, unzip,
     browser, browser_screenshot, browser_play, http, web_fetch, pdf_analyze. Executes `tools/call`.
   - Sticky session state: cwd, browser context (Playwright, per-tenant --user-data-dir), env,
     background procs — the MCP server instance is stateful for the session.
   - Large outputs → object storage via system/file, returned as an MCP `resource_link` (never inline).
   - MCP `sampling` DISABLED. Heartbeats; self-terminate on idle-timeout or lost control connection.
2) `api` → `runtime/worker` slice (the manager / dispatcher): sessions · k8s (manifest builder +
   create/delete) · browser (in-pod Chromium lifecycle) · idle (reaper) · profiles.
3) `api` → `runtime/task` slice (the queue): BullMQ on Redis; standard, delayed, repeatable jobs.

CONTRACTS: implement exactly the schemas, profiles, frames and job kinds in the reference below.
Follow CleanSlice conventions (gateway pattern, `I`-prefixed DI tokens, singular slice folders, `#`
aliases, no `any`).

SECURITY (non-negotiable): no long-lived secrets in the pod; short-lived per-session token only; KEK
never leaves api; NetworkPolicy default-deny + egress allowlist; read-only root fs, drop ALL caps,
non-root, automountServiceAccountToken:false; activeDeadlineSeconds hard cap; audit every session.

ACCEPTANCE: see the checklist at the bottom. Start at the v0.3 MVP scope.

Референс — контракты для реализации

Строка сессии

AgentRuntimeSession { agentId, taskId?, status, runtimeType, cpu/mem/storageLimit, ttlSeconds, k8sJobName, namespace, workerUrl, logsUrl, startedAt, lastActivityAt, stoppedAt } со состояниями pending → starting → running → idle → stopping → stopped (+ failed). См. Destroy.

Runtime-профили

Каталог пресетов → RuntimeProfile { mode, cpu, mem, storage, maxExecSeconds, idleSeconds } для None / Light / Browser / Heavy / Warm. Сборщик манифеста читает его. См. Deploy → режимы рантайма.

Control-канал = MCP (канал 3)

MCP поверх WebSocket'а, инициированного worker'ом (обратный транспорт). Worker — это MCP-сервер, worker-gateway в api — это MCP host/client; MCP session id ↔ наш sessionId.

jsonc
{ "method": "tools/list" }                                                      // host → worker (discover, allowlist-gated)
{ "method": "tools/call", "params": { "name": "browser.click",
    "arguments": { "selector": "#buy" } } }                                     // host → worker
{ "method": "notifications/progress", "params": { "progressToken": "c12",
    "message": "navigated to /cart" } }                                         // worker → host

Плюс handshake initialize (auth через WORKER_TOKEN), ready, heartbeat, release. MCP sampling отключён. Канал в общих чертах описан в Use → протокол; нормативный контракт провода — кто шлёт каждый кадр, что считается ответом, что происходит при молчании и правило версий — это Канал инструментов, и реализовывать надо его.

Джобы очереди

task dispatch (standard) · idle timer (delayed) · scheduled (repeatable) · ingestion (budgeted). Консьюмер = dispatcher, который создаёт k8s Job. См. Deploy → очередь.

Bootstrap env

SESSION_ID, CONTROL_URL, WORKER_TOKEN_FILE, TOOL_ALLOWLIST, скоуп хранилища.

Пропуск — это файл, а не значение: WORKER_TOKEN_FILE называет путь, по которому смонтирован projected Secret (/var/run/agentfy/token), и воркер читает его оттуда. WORKER_TOKEN в окружении остаётся — для запуска воркера вне Kubernetes, — а установить обе переменные нельзя: манифест, наполовину переведённый на том, иначе тихо оставил бы пропуск в окружении (006 T104).

MAX_EXEC_SECONDS и IDLE_SECONDS несут два срока этой сессии, прямо из её профиля. Воркер взводит первый таймер раньше, чем появляется управляющий канал, поэтому без них он откатывался к таблице профиля Light — 900 с и 90 с — на любом профиле: тяжёлой сессии сообщали четверть того часа, который у неё есть, а сборщик забирал под на тридцать секунд раньше, чем под ожидал (AGNT2-237). Кадр initialize несёт ту же пару, и воркер слушается меньшего из двух — поэтому одним кадром это было не починить: 900 меньше 3600. Обе переменные необязательны: их отсутствие означает таблицу Light, на что опирается каждый стенд, запускающий воркер руками, — но значение, которое стоит и не читается, отвергается: срок, тихо ставший 900 с, неотличим от срока, который таким и задумали.

Упорядоченные задачи

  1. v0.3 MVPruntime/task (dispatch + delayed idle-timer) · runtime/worker (sessions, k8s create/delete, Light-профиль) · образ worker (MCP-сервер: initialize + tools/list + exec/file) · обратный WS MCP-транспорт + регистрация на стороне host'а · idle-reaper. Доказывает message → Job → MCP attach → tools/call → result → reap.
  2. + Browser — Chromium in-pod, тулы browser*, Browser-профиль.
  3. + Конкурентность и надёжность — per-team-лимиты, retries/backoff + dead-letter.
  4. + Heavy / Warm — профили и размещение по нодам.
  5. + Scheduled — repeatable-джобы для agent/cron.

Критерии приёмки

  • [ ] Турн без тулов никогда ничего не ставит в очередь; турн с тулами ставит один раз для provision.
  • [ ] Одна MCP-сессия обслуживает много вызовов tools/call по одному обратному WebSocket (sticky cwd + контекст браузера).
  • [ ] Worker (MCP-сервер) дозванивается назад и аутентифицируется короткоживущим токеном на initialize; никаких других секретов в поде; MCP sampling выключен.
  • [ ] Control-трафик никогда не появляется в пользовательском чате; только курируемые статусы/артефакты.
  • [ ] Idle → reaped по окну профиля; выходные данные синхронизированы в system/file до удаления Job.
  • [ ] activeDeadlineSeconds и потолки max-idle принудительно соблюдаются; каждая сессия в аудите.

См. также