Tre modi diversi di non funzionare
“Non ha funzionato” non è una diagnosi. Prima di rimediare devi sapere quale delle tre situazioni hai davanti, e su quale superficie.
Un’esecuzione ferma è quella in cui il processo è vivo ma non avanza. Sul cloud agent di Copilot lo vedi dai session logs: da View session il log scorre in diretta e mostra i tool che l’agente sta usando. La documentazione avverte però che l’agente può sembrare bloccato per un po’ e poi ripartire, quindi il silenzio del log non è di per sé una condanna; se la sessione resta davvero bloccata va in timeout dopo un’ora. Il rimedio documentato è togliere l’assegnazione della issue a Copilot e riassegnarla.
Un’esecuzione parziale è più insidiosa, perché produce un artefatto. Il cloud agent lavora su un branch e apre una pull request in bozza: la pull request esiste, i commit ci sono, ma i controlli di CI non passano. Qui non c’è niente da riavviare, c’è da correggere: chiedi modifiche menzionando @copilot in un commento, oppure spingi tu dei commit sul branch. Attenzione: i workflow di Actions non partono automaticamente sui push di Copilot, serve Approve and run workflows nel merge box. Una pull request senza check verdi può quindi semplicemente non averli mai eseguiti. È la confusione tipica su cui l’esame ti mette alla prova: assenza di check non equivale a fallimento dell’agente.
Un’esecuzione fallita è terminata con esito negativo. Nel Copilot SDK in fleet mode la distinzione è esplicita nello stato: i todo passano per pending, in_progress e done, e un subagente che non può procedere si mette in blocked indicando il motivo. Gli eventi subagent.started e subagent.completed osservabili con session.on() ti dicono chi è partito e chi ha chiuso: chi è partito e non ha chiuso è il candidato bloccato.
Sul degrado del coordinamento la doc dell’SDK è netta: fleet mode non elimina il bisogno di una revisione da parte dell’agente padre, perché i worker paralleli possono partire da assunzioni incoerenti che l’orchestratore deve riconciliare. Lato amministrazione, la pagina AI controls dell’impresa elenca le sessioni recenti e le filtra per agent, organization, repository, status, timeframe e user.
Rimediare: rollback, ripresa, human-in-the-loop
Il rollback vero e proprio è una funzione della Copilot CLI, non del cloud agent. A sessione inattiva, due pressioni di Esc mostrano l’elenco dei punti di ripristino della sessione, uno per ogni prompt inviato; poi scegli fra riavvolgere solo la conversazione o riavvolgere anche i file, ripristinando le modifiche fatte da Copilot ma conservando le tue modifiche manuali. Ctrl+C invece agisce subito. I limiti contano: i file molto grandi non vengono tracciati, i turni che toccano un numero enorme di file non sono ripristinabili e le sessioni remote non si possono riavvolgere.
La ripresa dallo stato salvato appartiene invece al Copilot SDK. Se crei la sessione con un sessionId tuo, lo stato viene persistito su disco (checkpoint della conversazione, plan.md, artefatti) e resumeSession() la riapre dopo un riavvio; le chiavi API non vengono mai scritte su disco. Sempre nell’SDK, l’hook onErrorOccurred riceve fra i suoi campi error, errorContext e recoverable, e decide con errorHandling fra retry, skip e abort:
{ "errorHandling": "retry", "retryCount": 2, "userNotification": "Ritento la chiamata al tool" }
Restituire null lascia la gestione predefinita. Nel SDK Java questo hook non esiste e si usano EventErrorPolicy e EventErrorHandler.
Il human-in-the-loop è l’ultima rete. Per le automation del cloud agent è l’automation level del repository a fissare la soglia: con Full control ogni modifica è trattenuta per revisione, Cautious applica solo le modifiche a confidenza alta, Balanced applica quelle chiare e trattiene le ambigue, Full automation applica tutto. Ciò che è trattenuto attende nell’approvals panel della issue, dove accetti o rifiuti, e ogni modifica porta con sé una rationale e un confidence level.
Cambiare la flotta senza fermarla
Non serve fermare per correggere la rotta. Il cloud agent accetta steering input durante la sessione; nell’SDK lo stesso si ottiene con session.send() usando mode “immediate” per iniettare il messaggio nel turno corrente, oppure “enqueue” per accodarlo e farlo processare quando la sessione torna inattiva. Lo steering è best-effort: se l’agente ha già lanciato una chiamata a un tool, la correzione arriva dopo.
Aggiungere un agente a un flusso attivo è un’operazione di repository. I custom agents vivono in file .github/agents/NOME.agent.md da unire nel branch predefinito; nei GitHub Agentic Workflows il Markdown sta in .github/workflows/ e va compilato con gh aw compile, che genera il file .lock.yml eseguito da Actions. Aggiungere un file non tocca le esecuzioni in corso.
Il punto sottile è la sostituzione. Il versioning dei custom agent si basa sui commit SHA del file di profilo: un task appena assegnato usa la versione più recente per quel repository e quel branch, ma le interazioni dentro una pull request già aperta continuano a usare la stessa versione, per coerenza. Modificare il profilo non cambia quindi il comportamento a metà di una pull request in corso.
Ritirare un agente senza perdere le tracce
Ritirare significa smettere di usarlo, non cancellarne la storia. Chiudere una sessione singola si fa con Stop session nel visualizzatore di log: questo termina la run di GitHub Actions e conserva i commit già spinti, quindi il lavoro parziale resta ispezionabile. Le sessioni concluse si possono archiviare per togliere rumore dall’elenco senza distruggerle.
L’audit sopravvive all’agente. Nell’audit log gli eventi prodotti dagli agenti si isolano con il filtro actor:Copilot e portano i campi actor_is_agent e agent_session_id: è così che risali a quale sessione ha generato quale evento anche quando quell’agente non esiste più. L’impresa può inoltre inviare in streaming gli eventi delle sessioni verso una destinazione esterna, che è il modo corretto di conservare le tracce oltre la finestra di ritenzione dell’audit log. Sul locale, la Copilot CLI tiene le sessioni in ~/.copilot/session-state/ e un database che alimenta /chronicle, con cui interroghi il passato. Nell’SDK, session.disconnect() libera le risorse in memoria ma lascia i dati su disco, mentre client.deleteSession() li rimuove definitivamente e rende la sessione non più riprendibile: solo il primo gesto è compatibile con un requisito di auditabilità.
Da qui la regola pratica: la configurazione degli agenti va versionata nel repository come qualunque altro codice. Se il profilo è un file committato, il commit che ha guidato una sessione è ricostruibile; se vive solo nella schermata di qualcuno, quando l’agente viene ritirato la spiegazione di che cosa faceva se ne va con lui.