Перейти до вмісту

Життєвий цикл запуску агента

Запуск — це одне виконання одного агента, в одній розмові, на одному адаптері. Усе, що з ним пов’язано, відбувається на cc_server: клієнт надсилає повідомлення, а потім спостерігає, як у відповідь ллються події. У жодному клієнті немає шляху запуску.

Агентів будять із шести причин, які виконання несе як свій контекст пробудження, щоб агент знав, чому він прокинувся:

Причина пробудження Тригер
userMessage Хтось надіслав повідомлення в просторі або згадав агента
assignment Агенту призначили тікет
pipelineStep Крок конвеєра запустив його
childCompleted Дочірній тікет завершився
followUp Запланований пульс для подальшої роботи
recovery Шлях відновлення перезапустив його після збою

Контекст пробудження несе ідентифікатори, що супроводжують причину, — тікет, простір, повідомлення, запуск конвеєра — і вони впорскуються в середовище та промпт агента.

Промпт будується шарами, кожен з яких є позначеним розділом:

  • Ідентичність — власний ідентифікатор агента, його ім’я та ідентифікатор робочого простору, з явною вказівкою передавати ці самі UUID інструментам з областю робочого простору. Робочий простір невіддільний від агента, тож він присутній завжди.
  • Каталог інструментів і протоколи ресурсів, потім структура робочого простору.
  • Перевизначення системного промпту, якщо воно в агента є, потім персона (параметризована роллю) і бриф команди.
  • Навички — назви, прив’язані до агента.
  • Контракт і процедура виконання для поточного режиму.
  • Контекст пробудження і контекст згадки: хто викликав агента і хто є поряд.
  • Блок режиму — сформований із профілю можливостей режиму та його матеріалізованого списку інструментів, тож промпт ніколи не може назвати інструмент, якого у виконання насправді немає.
  • Контекст пам’яті — факти, вилучені для завдання.
  • Контекст розмови — недавня історія простору, обмежена дослівним вікном у 50 000 символів, незалежно від налаштованого розміру контексту агента. Старша історія не відкидається: агент дістає її на вимогу через get_messages, і семантично доречні старші повідомлення все одно спливають.

Команди поділені між двома місцями. /todo і /compact перехоплюються в редакторі повідомлень і свідомо ніколи не зберігаються як повідомлення та не надсилаються агенту — збереження /compact відсунуло б межу ущільнення на один хід назад і засмітило б транскрипт. /plan обробляється в обох: редактор повідомлень перемикає режим простору, і саме завдяки цьому набір інструментів, набір обмежень і промпт узгоджуються на цей хід і на кожен наступний. /goal, /loop і /skill:<name> обробляються всередині самого виконання і лише у вбудованому harness — /goal і /loop розпочинають автономну роботу з бюджетом витрат, а ім’я з префіксом skill: шукається як навичка, чиє тіло SKILL.md стає директивою ходу. Саме простір імен розділяє ці два словники: якби ім’я без префікса зіставлялося з навичками, навичку з назвою plan або compact назавжди затіняла б вбудована команда. Ім’я без префікса, яке не є вбудованою командою, усе ще зіставляється — для повідомлень, написаних до появи простору імен. Нерозпізнане ім’я просто проходить далі як звичайний текст.

Перш ніж щось запуститься, розмова отримує власний робочий корінь, а під ним — ізольований worktree з copy-on-write для кожного репозиторію. Типово це кожен репозиторій, прив’язаний до робочого простору; простір PR — або простір, створений із явним вибором, — готує лише дозволені, а розмова перевірки PR закріплює свій єдиний репозиторій за head-рефом pull request, тоді як решта лишаються на гілці за замовчуванням. Вихідний checkout ніколи не змінюється, а весь каталог розмови звільняється, коли простір видаляють.

Copy-on-write — єдина реалізація всюди, де постачається rift, на основі вбудованого нативного модуля. Файлова система, яка не вміє reflink, — або каталог даних на іншому томі, ніж репозиторій, — не дає підготувати worktree замість відкату. git worktree — це бекенд у Windows, де бекенда copy-on-write для збірки немає, і на інших хостах це не тиха деградація. Відсутній rift на платформі, де він постачається, — це зламане встановлення: сервер відмовляється запускатися, а не тихо відкочується, бо тихий відкат назавжди ховає поломку за повільнішим шляхом.

На кожне виконання, перш ніж запуститься будь-який процес, визначаються дві ідентичності.

Авторство Git. Коміти, які робить агент, створюються від імені агента — <Name> (agent) <agentId@agents.control-center.local> і в GIT_AUTHOR_*, і в GIT_COMMITTER_* — і ніколи не видаються за людину. Локальна частина — це UUID агента, а не його slug імені. Людину, яка зробила запит, зазначають трейлером Co-Authored-By:, який передається в середовищі та згадується в системному промпті. Явно задана тим, хто викликає, ідентичність завжди переважає обидві.

Ідентичність на хості коду. Облікові дані GitHub для виконання завжди належать лише брокеру — токен інсталяції App з областю репозиторію або його резервний PAT із середовища — і ніколи не є власним збереженим токеном учасника, який зробив запит. actingUserId обмежує резервний PAT, щоб учасник, який не є власником сервера, не успадковував досяжність сервера; він не накладає особистий токен на середовище агента.

Облікові дані провайдера моделей визначаються у фіксованому порядку, і цей порядок важливий:

  1. перевизначення середовища для конкретного адаптера;
  2. середовище того, хто викликає;
  3. сховище облікових даних сервера (з оновленням токена OAuth, якщо спливає строк його дії);
  4. середовище процесу.

Оскільки перевизначення для адаптера стоїть першим, воно тихо переважає обліковий запис провайдера, підключений у застосунку. Якщо витрати виконання потрапляють на неправильний обліковий запис, це перевизначення — перше місце, куди варто зазирнути. Облікові дані провайдера глобальні для хоста — спільні для всіх робочих просторів у цьому встановленні.

Токен GitHub запуску надходить від брокера облікових даних: це токен лише для читання з областю репозиторію worktree. Push проходить через шлюз запусків агентів, який перед передачею запитує правило Надіслати на віддалений репозиторій, а ключ тікетів не впорскується. Див. Пісочниця та безпека.

Виконання породжується зі своїм worktree як робочим каталогом, а для Claude Code — ще й зі згенерованою конфігурацією MCP, щоб агент міг дістатися до набору інструментів Control Center. ACP і bash harness отримують очищене середовище; Claude Code через NoSandboxAdapter успадковує середовище хоста.

Виконання повертає типізовану послідовність подій, яку потоковий процесор зберігає як дельти повідомлень, згортає в сегменти транскрипту й перетворює на події обміну повідомленнями:

Подія Що вона несе
thinking Вивід міркувань, відображений у тексті
text Видимий вивід
toolCall Виклик інструмента з його ідентифікатором і структурованими аргументами
toolResult Відповідний результат; позначений, якщо стався збій або потік частковий
usage Кількість токенів і вартість за вікно вимірювання
error Помилка; зі структурованим кодом адаптера, якщо той його надав
sandboxViolation ОС відхилила системний виклик. Надсилається лише там, де пісочниця справді загортає процес — див. заувагу вище
debug Діагностика під час виконання (маркери запуску, рішення обмежень, нагадування щодо контракту)
done Виконання завершилося

Тут свідомо немає жодного обмеження на кількість ходів. Жорсткий ліміт ітерацій убиває законну довгу роботу (міграції, прибирання після розгалуження) і не ловить нічого, чого не зловили б раніше запобіжники нижче. Виконання завершується, коли:

  • модель зупиняється сама;
  • людина зупиняє його або перебирає керування розмовою (це призупиняє вбудований harness на наступній чистій межі ходу — виконання Claude Code, яке не має безпечної межі, натомість зупиняється);
  • спрацьовує сторожовий таймер тиші. Жодного виводу протягом порогового часу — і сеанс завершується збоєм silentRun. Типово це 15 хвилин, а в переважно читальних режимах (огляд і план) — 10; агент може перевизначити його в межах від 1 до 240 хвилин. Таймер озброюється, коли дочірній процес повідомляє свій PID, тож він охоплює CLI Claude Code — і не вбудований harness, який нічого не породжує;
  • спрацьовує обмеження витрат — але лише для автономних команд.

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

У підсумку звичайний інтерактивний хід у вбудованому harness не має ні обмеження на кількість ходів, ні обмеження витрат, ні сторожового таймера тиші. Він завершується, коли зупиняється модель або коли його зупиняєте ви. Це свідомий компроміс — усі альтернативи вбивають законну довгу роботу — але він означає, що інтерактивне виконання без нагляду не обмежує ніщо, крім власного розсуду моделі.

Під час виконання повідомлення, надіслане агенту, який працює, ставиться в чергу як коригувальне і зчитується на межі наступного ходу, тож ви можете підштовхнути виконання, не вбиваючи його. Коригування, призупинення, субагенти й контракт завершення — це можливості вбудованого harness; у Claude Code немає жодної з них.

Кожен запуск пише AgentRunLog: час початку й завершення, резюме, кількість токенів і оцінену вартість (зокрема вартість, зведену від субагентів), адаптер і модель, ідентифікатор процесу й шлях до журналу, розмову та будь-який тікет чи запуск конвеєра, до якого він належить, а також два класифікаційні поля, які несуть більшу частину правди.

  • Статус — грубий: pending, running, completed, error.
  • Живучість — точніший показник: alive, productive, completed, blocked, empty, looping, failed, stalled, dead.
  • Сімейство помилок змістовно групує збої: transientUpstream, sandboxInfrastructure, budgetExceeded, processLost, silentRun, unknown.

Закриття виконання публікує AgentRunCompleted, і від нього залежить багато чого: зведення витрат конвеєра, відновлення кроку конвеєра, що чекав на виконання, завершення тікета, який за ним стоїть, переведення оркестрації в кінцевий стан, рішення наглядача цілей продовжити чи зупинитися, роль перевіряльника та оцінювання бюджету після виконання. Список присутності оновлюється окремо — за останніми журналами виконань, а не за подією. Сповіщення «Агент завершив роботу» в цьому списку немає: подія спрацьовує, коли закінчується потік процесу, ще до запису відповіді, тож сповіщенням є MessageReceived цього ходу, що публікується після збереження повідомлення.

Застосування бюджету — це реакція, а не бар’єр. Коли виконання завершується, оцінювач порівнює витрати агента з початку місяця з його чинною межею (пов’язана політика бюджету, якщо вона є, інакше — власна місячна цифра агента; нуль означає без обмежень). Перетин м’якого порогу записує інцидент-попередження; вичерпання бюджету записує жорсткий інцидент і перемикає статус життєвого циклу агента на paused в оргсхемі. Запуск усе одно приймає роботу від цього агента. Тригер конвеєра BudgetThresholdCrossed може розпочати подальшу роботу з тієї самої події.

Кожен журнал виконання може нести родовід повторів — ідентифікатор батьківського виконання, лічильник спроб і резюме продовження. Дерево виконань розмови показує номер спроби, коли він не нульовий. «Спробувати ще раз» із чату — це новий запуск із новим журналом виконання.