Salta ai contenuti

Ciclo di vita dell'invio degli agenti

Un invio è una singola esecuzione di un singolo agente, in una singola conversazione, su un singolo adapter. Tutto ciò che lo riguarda accade su cc_server: il client invia un messaggio e poi osserva gli eventi che tornano in streaming. Non esiste alcun percorso di invio in nessun client.

Gli agenti vengono risvegliati per sei motivi, che l’esecuzione porta con sé come contesto di risveglio così che l’agente sappia perché è sveglio:

Motivo del risveglio Attivazione
userMessage Qualcuno ha inviato un messaggio in uno spazio, oppure ha menzionato l’agente
assignment Un ticket è stato assegnato all’agente
pipelineStep Un passaggio di pipeline lo ha inviato
childCompleted Un ticket figlio è terminato
followUp Un heartbeat di follow-up pianificato
recovery Il percorso di ripristino ha rilanciato l’invio dopo un errore

Il contesto di risveglio porta con sé gli id che accompagnano il motivo — ticket, spazio, messaggio, esecuzione di pipeline — e vengono iniettati nell’ambiente e nel prompt dell’agente.

Il prompt è costruito a strati, ciascuno dei quali è una sezione etichettata:

  • Identità — l’id, il nome e l’id dello spazio di lavoro dell’agente stesso, con un’istruzione esplicita a passare esattamente quegli UUID agli strumenti con ambito di spazio di lavoro. Lo spazio di lavoro è intrinseco all’agente, quindi è sempre presente.
  • Catalogo degli strumenti e protocolli delle risorse, poi la struttura dello spazio di lavoro.
  • Override del prompt di sistema, se l’agente ne ha uno, poi la persona (parametrizzata per ruolo) e il brief del team.
  • Skill — i nomi presenti sull’agente.
  • Contratto di esecuzione e procedura per la modalità corrente.
  • Contesto di risveglio e contesto delle menzioni: chi ha convocato l’agente e l’elenco di chi gli sta intorno.
  • Blocco della modalità — generato dal profilo di capacità della modalità e dal suo elenco di strumenti materializzato, così un prompt non può mai nominare uno strumento che l’esecuzione non ha davvero.
  • Contesto di memoria — fatti recuperati per l’attività.
  • Contesto della conversazione — cronologia recente dello spazio, limitata a 50.000 caratteri di finestra letterale, indipendentemente dalla dimensione del contesto configurata per l’agente. La cronologia più vecchia non viene eliminata per troncamento: l’agente la recupera su richiesta con get_messages e i messaggi più vecchi semanticamente rilevanti emergono comunque.

I comandi sono divisi tra due punti. /todo e /compact vengono intercettati nel compositore e di proposito non vengono mai memorizzati come messaggi né inviati all’agente — memorizzare /compact sposterebbe indietro di un turno il taglio della compattazione e inquinerebbe la trascrizione. /plan è gestito in entrambi i punti: il compositore cambia la modalità dello spazio, ed è ciò che fa concordare superficie degli strumenti, preset dei guardrail e prompt per questo turno e per ogni turno successivo. /goal, /loop e /skill:<name> sono gestiti all’interno dell’esecuzione stessa e solo sull’harness integrato — /goal e /loop avviano lavoro autonomo con un budget di costo, e un nome con prefisso skill: viene cercato come una skill il cui corpo SKILL.md diventa la direttiva del turno. È il namespace a tenere separati i due vocabolari: risolvere un nome nudo rispetto alle skill significava che una skill chiamata plan o compact veniva oscurata in modo permanente dal comando integrato. Un nome nudo non integrato viene comunque risolto, per i messaggi scritti prima che il namespace esistesse. Un nome non riconosciuto passa semplicemente come testo normale.

Prima che qualsiasi cosa venga eseguita, la conversazione ottiene una propria radice di lavoro, con sotto di essa un worktree copy-on-write isolato per ogni repo. Per impostazione predefinita si tratta di ogni repo collegato allo spazio di lavoro; uno spazio PR — o uno spazio creato con una selezione esplicita — predispone solo quelli presenti nella lista consentita, e una conversazione di revisione PR fissa il suo unico repo al ref head della pull request mentre gli altri restano sul loro branch predefinito. Il checkout di origine non viene mai modificato e l’intera directory della conversazione viene recuperata quando lo spazio viene eliminato.

Il copy-on-write è l’unica implementazione ovunque rift sia distribuito, sostenuta dal native incluso. Un filesystem che non sa fare reflink — o una data dir su un volume diverso da quello del repo — fa fallire la predisposizione invece di ripiegare su un’alternativa. git worktree è il backend su Windows, dove non c’è alcun backend copy-on-write da compilare, e non è una degradazione silenziosa sugli altri host. Un rift mancante su una piattaforma che lo distribuisce è un’installazione rotta — il server si rifiuta di avviarsi invece di ripiegare in silenzio, perché un fallback silenzioso nasconde il guasto dietro un percorso più lento per sempre.

Per ogni esecuzione vengono risolte due identità, prima che qualsiasi processo venga avviato.

Paternità Git. I commit creati da un agente sono attribuiti all’agente — <Name> (agent) <agentId@agents.control-center.local> sia in GIT_AUTHOR_* sia in GIT_COMMITTER_* — senza mai impersonare una persona. La parte locale è l’UUID dell’agente, non lo slug del suo nome. Alla persona richiedente viene riconosciuto un trailer Co-Authored-By:, trasportato nell’ambiente e indicato nel prompt di sistema. Un’identità esplicita impostata dal chiamante vince sempre su entrambe.

Identità della forge. La credenziale GitHub dell’esecuzione è sempre e solo quella del broker — un token di installazione dell’App con ambito sul repo, o il suo fallback PAT dall’ambiente — mai il token memorizzato del membro richiedente. actingUserId delimita il fallback PAT, così un membro che non è il proprietario del server non eredita la portata del server; non sovrappone un token personale all’ambiente dell’agente.

Le credenziali del provider di modelli vengono risolte in un ordine fisso e l’ordine conta:

  1. un override dell’ambiente relativo al singolo adapter,
  2. l’ambiente del chiamante,
  3. l’archivio delle credenziali del server (aggiornando un token OAuth se è prossimo alla scadenza),
  4. l’ambiente del processo.

Poiché l’override per adapter viene per primo, batte in silenzio un account del provider collegato nell’app. Se un’esecuzione viene addebitata sull’account sbagliato, quell’override è il primo posto da controllare. Le credenziali del provider sono globali per l’host — condivise tra tutti gli spazi di lavoro dell’installazione.

Il token GitHub dell’esecuzione proviene dal broker delle credenziali: un token di sola lettura, limitato al repo del worktree. Un push passa dal gateway delle esecuzioni degli agenti, che interroga la regola Eseguire il push a un remoto prima di inoltrarlo, e non viene iniettata alcuna chiave di ticketing. Vedi Sandbox e sicurezza.

L’esecuzione viene avviata con il suo worktree come directory di lavoro e — per Claude Code — una configurazione MCP generata, così che l’agente possa raggiungere la superficie degli strumenti di Control Center. ACP e bash dell’harness ricevono un ambiente ripulito; Claude Code tramite NoSandboxAdapter eredita l’ambiente dell’host.

L’esecuzione restituisce in streaming una sequenza di eventi tipizzati, che il processore di stream persiste come delta di messaggio, ripiega in segmenti di trascrizione e trasforma in eventi di messaggistica:

Evento Cosa trasporta
thinking Output di ragionamento, visualizzato inline
text Output visibile
toolCall Un’invocazione di strumento, con il suo id e argomenti strutturati
toolResult Il risultato corrispondente, contrassegnato quando ha prodotto un errore o è uno stream parziale
usage Conteggi di token e costo per una finestra di misurazione
error Un errore, con il codice strutturato dell’adapter quando ne ha segnalato uno
sandboxViolation Il sistema operativo ha negato una chiamata di sistema. Emesso solo dove un sandbox avvolge davvero il processo — vedi la nota sopra
debug Diagnostica di runtime (marcatori di avvio, decisioni del guard, sollecitazioni del contratto)
done L’esecuzione è terminata

Non esiste deliberatamente alcun tetto di turni, da nessuna parte. Un conteggio fisso di iterazioni uccide il lavoro lungo legittimo (migrazioni, pulizia di fan-out) e non intercetta nulla che le protezioni descritte sotto non intercettino prima. Un’esecuzione termina quando:

  • il modello si ferma da solo;
  • una persona la ferma, oppure prende il controllo della conversazione (il che mette in pausa l’harness integrato al suo prossimo confine di turno pulito — un’esecuzione di Claude Code, che non ha un confine sicuro, viene invece fermata);
  • scatta il watchdog del silenzio. Nessun output per la soglia e la sessione viene terminata con un errore silentRun. Il valore predefinito è 15 minuti, che scende a 10 nelle modalità prevalentemente in lettura (review e plan); un agente può sovrascriverlo tra 1 e 240 minuti. Il watchdog viene armato quando un processo figlio segnala il proprio PID, quindi copre la CLI di Claude Code — non l’harness integrato, che non genera alcun processo;
  • scatta un limite di costo — ma solo per i comandi autonomi.

La protezione anti doom-loop non è un terminatore: tre chiamate di strumento identiche di fila e il ciclo guida l’agente a cambiare approccio.

Messi insieme, un normale turno interattivo sull’harness integrato non ha tetto di turni, né limite di costo, né watchdog del silenzio. Termina quando il modello si ferma o quando lo fermi tu. È uno scambio deliberato — le alternative uccidono tutte il lavoro lungo legittimo — ma significa davvero che un’esecuzione interattiva non presidiata è delimitata da nient’altro che dal giudizio del modello stesso.

A metà esecuzione, un messaggio inviato a un agente in corso viene accodato come guida e consumato al confine del turno successivo, così puoi sollecitare un’esecuzione senza ucciderla. La guida, la pausa, i sottoagenti e il contratto di completamento sono funzionalità dell’harness integrato; Claude Code non ne ha nessuna.

Ogni invio scrive un AgentRunLog: ora di inizio e di fine, riepilogo, conteggi di token e costo stimato (incluso il costo aggregato dai sottoagenti), adapter e modello, id del processo e percorso del log, la conversazione e qualsiasi ticket o esecuzione di pipeline a cui appartiene, più due campi di classificazione che racchiudono gran parte della verità.

  • Stato è grossolano: pending, running, completed, error.
  • Vitalità è la lettura più fine: alive, productive, completed, blocked, empty, looping, failed, stalled, dead.
  • Famiglia di errore raggruppa i guasti in modo utile: transientUpstream, sandboxInfrastructure, budgetExceeded, processLost, silentRun, unknown.

La chiusura dell’esecuzione pubblica AgentRunCompleted e da essa dipende molto: l’aggregazione dei costi della pipeline, la ripresa di un passaggio di pipeline che era in attesa dell’esecuzione, il completamento del ticket sottostante, la mappatura di un’orchestrazione su uno stato terminale, la decisione di continuare o fermarsi del supervisore degli obiettivi, il ruolo di revisore e la valutazione del budget a esecuzione conclusa. L’elenco della presenza segue separatamente, osservando i log di esecuzione recenti anziché l’evento. La notifica «agente completato» non è in questo elenco: l’evento scatta quando termina lo stream del processo, prima che la risposta venga scritta, quindi la notifica è il MessageReceived del turno, pubblicato una volta che il messaggio è stato salvato.

L’applicazione del budget è una reazione, non un cancello. Quando un’esecuzione termina, il valutatore confronta la spesa dell’agente dall’inizio del mese con il suo tetto effettivo (una policy di budget collegata, se esiste, altrimenti la cifra mensile dell’agente stesso; zero significa illimitato). Superare la soglia soft registra un incidente di avviso; esaurire il budget registra un incidente hard e porta lo stato del ciclo di vita dell’agente a paused sull’organigramma. L’invio accetta comunque lavoro da quell’agente. Un trigger di pipeline BudgetThresholdCrossed può avviare lavoro di follow-up dallo stesso evento.

Ogni log di esecuzione può portare con sé una discendenza di tentativi — un id dell’esecuzione padre, un contatore di tentativi e un riepilogo di continuazione. L’albero delle esecuzioni della conversazione mostra il numero del tentativo quando è diverso da zero. Un «riprova» dalla chat è un nuovo invio con un log di esecuzione nuovo.