---
title: Esecuzioni di workflow
url: https://platform.claude.com/docs/it/managed-agents/workflow-runs
description: "Segui le esecuzioni di workflow di un agente: i loro stati ed eventi, quando il lavoro è terminato, le richieste mentre un'esecuzione è aperta, budget e limiti."
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

Un **workflow** (flusso di lavoro) è un programma che un agente scrive per eseguire molti agenti e combinare ciò che restituiscono. Un **workflow run** (esecuzione di workflow) è l'esecuzione di un workflow. **[Dynamic workflows](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#dynamic-workflows)** (workflow dinamici) è la funzionalità che consente a un agente di scrivere workflow e avviare esecuzioni. La attivi o disattivi con l'impostazione `workflows` (csharp, go: `Workflows`) nel blocco `multiagent` (csharp, go: `Multiagent`) dell'agente.

Il server esegue un workflow in background. I suoi agenti lavorano in [thread di sessione](https://platform.claude.com/docs/it/managed-agents/session-threads) che il server crea man mano che il workflow ne ha bisogno. Segui le esecuzioni sullo [stream di eventi](https://platform.claude.com/docs/it/managed-agents/events-and-streaming) della sessione. Per fermare un'esecuzione, chiedi all'agente di fermarla (consulta [Interrompere una sessione con esecuzioni aperte](https://platform.claude.com/docs/it/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).

## Come funzionano i workflow dinamici

L'agente eseguito dalla sessione scrive ogni workflow per il lavoro che descrivi. Un workflow è un programma: esegue altri agenti, raccoglie ciò che ciascuno restituisce e combina i risultati. In questo modo, l'agente può affrontare un'attività troppo grande per una singola conversazione, come la revisione di centinaia di documenti. Durante un'esecuzione, l'agente può continuare a lavorare o terminare il proprio turno, e può controllare lo stato dell'esecuzione.

<Frame>
  ![Livelli di un "workflow run" (esecuzione di workflow): l'esecuzione, le sue due "phases" (fasi) e gli "agent threads" (thread degli agenti) in ciascuna. I risultati passano da una fase alla successiva.](https://platform.claude.com/docs/it/images/workflow-anatomy.svg)
</Frame>

Il diagramma mostra un esempio. Ogni workflow che l'agente scrive ha le proprie fasi e i propri agenti. Un'esecuzione ha questi livelli:

* **Esecuzione di workflow:** Il server esegue il workflow in background, come un'unica esecuzione di workflow. Una sessione può avere diverse esecuzioni aperte contemporaneamente.
* **Fasi:** Un workflow può suddividere il proprio lavoro in fasi. Una fase è uno stadio dell'esecuzione con un proprio nome, come "Leggi i contratti". Segui l'avanzamento di un'esecuzione tramite i suoi eventi di fase.
* **Thread degli agenti:** In una fase, il programma esegue agenti. Ogni agente lavora nel proprio [thread di sessione](https://platform.claude.com/docs/it/managed-agents/session-threads), su un prompt scritto dal programma. Un agente in un'esecuzione può essere un agente inline, che il programma definisce da sé, oppure un agente predefinito, che elenchi nella [lista `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) di `workflows` (csharp, go: `Workflows`)](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#predefined-and-inline-agents). Per ciò che mostra ciascun thread, consulta [I thread di un'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#a-runs-threads).

Il programma può fare quanto segue:

* **Eseguire agenti contemporaneamente:** Il programma può eseguire molti agenti contemporaneamente, operazione chiamata "fan-out" (distribuzione in parallelo). Nel diagramma, tre agenti leggono contratti nella prima fase.
* **Passare risultati da un agente all'altro:** Ogni agente restituisce il proprio risultato al programma. Il programma può passare quel risultato a un altro agente. Nel diagramma, l'agente nella seconda fase lavora con ciò che i primi tre hanno restituito. Gli agenti di un'esecuzione lavorano anche con gli stessi file, nella sandbox della sessione.
* **Compiere il passo successivo da solo:** Il risultato di un agente va al programma, non all'agente eseguito dalla sessione. Il programma determina quali agenti eseguire successivamente e scrive i loro prompt.
* **Ripetere e scegliere:** All'interno di una fase, il programma può ripetere il lavoro e scegliere il passo successivo in base a ciò che un agente ha restituito. Ad esempio, può far rivedere una bozza finché una revisione non viene superata o non si esaurisce un numero prestabilito di cicli. Nel diagramma, il programma può ripetere un passaggio all'interno della seconda fase.
* **Gestire un agente che fallisce:** Quando uno dei suoi agenti fallisce, il server di solito esegue quell'agente ancora una volta, su un nuovo thread, mentre gli altri agenti dell'esecuzione continuano a lavorare. Se fallisce di nuovo, il programma può gestire l'errore o lasciare che termini l'esecuzione. Se il programma gestisce un errore, l'esecuzione può comunque terminare come `completed`, quindi chiedi all'agente eseguito dalla sessione di riferire cosa non è riuscito.

Quando l'esecuzione termina, l'agente eseguito dalla sessione ottiene un turno per leggere ciò che l'esecuzione ha fatto. Può quindi risponderti o avviare un'altra esecuzione. [Eventi dell'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#run-events) elenca i casi in cui quel turno arriva più tardi o non arriva.

Puoi indicare come un'esecuzione svolge il lavoro, ad esempio come suddivide il lavoro e cosa fa quando un agente fallisce. Consulta [Indicare all'agente quando usare un'esecuzione](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#tell-the-agent-when-to-use-a-run).

Non c'è alcun passaggio di approvazione prima dell'avvio di un'esecuzione: l'agente avvia un'esecuzione nello stesso turno in cui scrive il workflow. Per esaminare prima un piano, chiedi all'agente di descrivere l'esecuzione e di attendere il tuo via libera. All'avvio di un'esecuzione, `workflow_run.created` ne mostra il nome, la descrizione e le fasi. Se si avvia un'esecuzione che non hai approvato, chiedi all'agente di fermarla (consulta [Interrompere una sessione con esecuzioni aperte](https://platform.claude.com/docs/it/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).

## Come un'esecuzione passa da uno stato all'altro

<Frame>
  ![Stati di un "workflow run" (esecuzione di workflow): "running" (in corso), "idle" (inattiva) ed "ended" (terminata), e cosa sposta un'esecuzione da uno stato all'altro.](https://platform.claude.com/docs/it/images/workflow-run-states.svg)
</Frame>

Un'esecuzione inizia come in corso o come inattiva. Il raggiungimento del budget, ad esempio, mette in pausa un'esecuzione in corso, rendendola inattiva; aumentare o rimuovere il budget la fa poi ripartire, a meno che non l'abbia messa in pausa anche un'interruzione. Un'esecuzione in corso termina quando il suo workflow finisce, l'agente la ferma, fallisce, la sua durata massima scade o la sessione viene archiviata. Anche un'esecuzione inattiva può terminare, ad esempio quando l'agente la ferma o la sessione viene archiviata.

Un'esecuzione è **aperta** dal suo evento `workflow_run.created` fino al suo evento `workflow_run.status_ended`, che sia in corso o inattiva. Un'esecuzione è inattiva mentre è in pausa, ad esempio al raggiungimento del budget della sessione. Un'esecuzione ha una [durata massima](https://platform.claude.com/docs/it/managed-agents/workflow-runs#limits), che l'agente può impostare quando avvia l'esecuzione. Il tempo che un'esecuzione trascorre in attesa del tuo client conta ai fini di tale durata. Una pausa non impedisce alla durata di un'esecuzione di scorrere, quindi un'esecuzione che resta in pausa può terminare con `timeout_error`. Gli eventi seguenti segnalano l'avvio di un'esecuzione, le sue fasi e la sua fine. Anche una pausa al raggiungimento del budget ne invia uno. Una pausa dopo un'interruzione potrebbe non inviarne nessuno. Ogni evento `workflow_run.*` include `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), che è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) solo in un `workflow_run.error` quando non è stata creata alcuna esecuzione.

## Eventi dell'esecuzione

Gli eventi dell'esecuzione arrivano sullo stream di eventi della sessione, che è lo stream del thread principale, e anche l'elenco degli eventi della sessione li restituisce. Gli eventi dell'esecuzione non attivano [webhook](https://platform.claude.com/docs/it/managed-agents/webhooks). Gli eventi di stato dei thread dell'esecuzione arrivano sullo stesso stream. Ciascuno indica il proprio thread in `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), e i thread di un'esecuzione sono quelli il cui evento `session.thread_created` aveva il `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) dell'esecuzione.

| Evento                                                   | Quando arriva                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Cosa fare                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `workflow_run.created`                                   | L'agente ha avviato un'esecuzione. Include `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) (`wrun_…`), il `name` (csharp, go: `Name`) e la `description` (csharp, go: `Description`) dell'esecuzione, e `phases` (csharp, go: `Phases`), le fasi dichiarate dal workflow, ciascuna con un `id` (csharp, go: `ID`), un `name` (csharp, go: `Name`) e una `description` (csharp, go: `Description`). Una `description` (csharp, go: `Description`) è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) quando il workflow non ne fornisce alcuna. `phases` (csharp, go: `Phases`) è sempre presente e può essere vuoto. Il `name` (csharp, go: `Name`) e la `description` (csharp, go: `Description`) dell'esecuzione e delle fasi sono testo scritto dal modello, quindi possono ripetere parole della tua richiesta. Il `name` (csharp, go: `Name`) di un'esecuzione può anche essere assegnato dal server. | Tieni traccia dell'esecuzione come aperta. Mostrane il `name` (csharp, go: `Name`) e l'avanzamento rispetto a `phases` (csharp, go: `Phases`).                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `workflow_run.status_running`                            | Quando l'esecuzione inizia a essere eseguita, il che può avvenire un po' dopo `created`, e ogni volta che riprende dopo una pausa al raggiungimento del budget. Una ripresa dopo un'interruzione potrebbe non inviarlo. Un'esecuzione che inizia inattiva potrebbe ricevere prima `workflow_run.status_idle`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | Mostra l'esecuzione come in corso.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `workflow_run.status_idle`                               | L'esecuzione è stata messa in pausa, ad esempio al raggiungimento del budget della sessione. L'evento non dice perché. Una pausa dopo un'interruzione potrebbe non inviarlo.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Per continuare, consulta [Costi e budget](https://platform.claude.com/docs/it/managed-agents/workflow-runs#cost-and-budgets) o [Interrompere una sessione con esecuzioni aperte](https://platform.claude.com/docs/it/managed-agents/workflow-runs#interrupt-a-session-with-runs-open).                                                                                                                                                                                                                                                                                                                 |
| `workflow_run.phase_started`, `workflow_run.phase_ended` | Il workflow è entrato in una fase o ne è uscito, oppure la fine dell'esecuzione ha chiuso una fase ancora aperta. L'evento di fine non dice se il lavoro della fase è terminato. Entrambi includono `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`). L'evento di fine ha anche `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`), l'`id` (csharp, go: `ID`) dell'evento di inizio che chiude. Nessuno dei due contiene il nome della fase: cercalo tramite `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`) in `phases` (csharp, go: `Phases`) di `workflow_run.created`.                                                                                                                                                                                                                     | Aggiorna l'avanzamento. Le fasi vengono eseguite una alla volta, nell'ordine di `phases` (csharp, go: `Phases`), ciascuna al massimo una volta, ma l'API non lo garantisce. Associa la fine di una fase al suo inizio tramite `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`). Gestisci più di una fase aperta, una fase che non è in `phases` (csharp, go: `Phases`) e una fase elencata che non inizia mai, anche in un'esecuzione che viene completata. Ogni fase che inizia termina anche, prima del `workflow_run.status_ended` dell'esecuzione. |
| `workflow_run.status_ended`                              | L'esecuzione è terminata. È sempre l'ultimo degli eventi `workflow_run.*` dell'esecuzione. Include `result` (csharp, go: `Result`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Leggi `result` (csharp, go: `Result`) (tabella successiva). L'agente ottiene quindi un turno per leggere come è terminata l'esecuzione. Al raggiungimento del budget, o mentre il thread principale attende il tuo client, quel turno arriva più tardi. Dopo un'interruzione, quel turno potrebbe non arrivare: invia un `user.message` oppure leggi tu stesso `result` (csharp, go: `Result`). Dopo un'archiviazione o una terminazione, non arriva.                                                                                                                                                  |
| `workflow_run.error`                                     | Il server segnala un errore di un'esecuzione, o un avvio che ha rifiutato. Un'esecuzione che termina in `error` riceve questo evento, con lo stesso errore, prima del suo `workflow_run.status_ended`. Include `error` (csharp, go: `Error`): un `type` (csharp, go: `Type`) e un `message` (csharp, go: `Message`) che è sicuro registrare nei log. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) quando non è stata creata alcuna esecuzione.                                                                                                                                                                                                                                                                                                                                                                                                       | Registralo nei log e non considerarlo come la fine dell'esecuzione. Se `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`), nessuna esecuzione è stata avviata. Altrimenti continua a tenere traccia dell'esecuzione fino al suo `workflow_run.status_ended`.                                                                                                                                                                                                                      |

| `result`                         | Significato                                                                                                                                                                                                                                                                                                                                                                                                     |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{"type": "completed"}`          | Il workflow ha terminato l'esecuzione. Il risultato non dice se il lavoro è andato a buon fine. Un'esecuzione può terminare `completed` anche se il lavoro sui suoi thread è fallito, o non è stato possibile creare un thread. Per trovare il lavoro non riuscito, leggi gli eventi di ciascuno dei [thread dell'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#a-runs-threads). |
| `{"type": "stopped"}`            | L'agente ha fermato l'esecuzione, oppure la sessione è stata archiviata. L'evento non dice quale dei due. Non considerarle le uniche cause.                                                                                                                                                                                                                                                                     |
| `error` con `timeout_error`      | L'esecuzione ha raggiunto la sua [durata massima](https://platform.claude.com/docs/it/managed-agents/workflow-runs#limits), che l'agente può impostare.                                                                                                                                                                                                                                                         |
| `error` con `program_error`      | Il workflow è fallito. Il suo codice è fallito, oppure ha violato una regola per i workflow, diversa da un limite. Oppure uno dei thread dell'esecuzione è fallito, o non è stato possibile crearlo, e il workflow ha lasciato che ciò terminasse l'esecuzione.                                                                                                                                                 |
| `error` con `thread_limit_error` | L'esecuzione ha superato il suo [limite sugli agenti che un workflow avvia](https://platform.claude.com/docs/it/managed-agents/workflow-runs#limits).                                                                                                                                                                                                                                                           |
| `error` con `unknown_error`      | Il server non ha potuto proseguire l'esecuzione, oppure l'esecuzione ha superato uno degli altri limiti del server sui workflow.                                                                                                                                                                                                                                                                                |

Un risultato di errore ha l'aspetto di `{"type": "error", "error": {"type": "timeout_error", "message": "..."}}`, dove `message` è sicuro da registrare nei log. Tratta un `result.type` non riconosciuto come un'esecuzione terminata in qualche altro modo, e un `error.type` non riconosciuto come un errore. Quando qualcosa da cui la sessione dipende fallisce, come il modello, un server MCP, le credenziali o la fatturazione, lo stream del thread che fallisce riceve un `session.error`. Questo di per sé non termina un'esecuzione. Ma se fa fallire uno dei thread dell'esecuzione, e il workflow lascia che ciò termini l'esecuzione, l'esecuzione termina con `program_error`.

Ad esempio, chiedi all'[agente di revisione dei contratti](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) quali tra 300 contratti contengono una clausola di cambio di controllo, e l'agente avvia un'esecuzione:

1. `workflow_run.created` assegna all'esecuzione il nome "Find change-of-control clauses" ed elenca le fasi "Read the contracts" e "Reconcile the findings" in `phases` (csharp, go: `Phases`). Segue poi `workflow_run.status_running`.
2. Gli eventi di fase segnano ciascuna fase, e ogni thread creato dall'esecuzione invia `session.thread_created` con il `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) dell'esecuzione.
3. `workflow_run.status_ended` arriva con `result: {"type": "completed"}`.
4. L'agente risponde "41 dei 300 contratti ne contengono una", e `session.status_idle` arriva con `end_turn`.

Il primo evento dell'esecuzione elenca le sue fasi:

```json
{
  "type": "workflow_run.created",
  "id": "sevt_01abc...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "name": "Find change-of-control clauses",
  "description": "Reads each contract and lists those that have the clause.",
  "phases": [
    {
      "id": "wrph_01Kd3a1f3",
      "name": "Read the contracts",
      "description": "Reads each contract for the clause."
    },
    { "id": "wrph_01Kd3b7c9", "name": "Reconcile the findings", "description": null }
  ],
  "processed_at": "2026-10-09T14:01:45Z"
}
```

Ogni evento di fase indica la propria fase tramite `workflow_run_phase_id`. Si tratta di un `id` in `phases`, ma l'API non lo garantisce:

```json
{
  "type": "workflow_run.phase_started",
  "id": "sevt_01def...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "workflow_run_phase_id": "wrph_01Kd3a1f3",
  "processed_at": "2026-10-09T14:01:46Z"
}
```

L'ultimo evento dell'esecuzione riporta come è terminata:

```json
{
  "type": "workflow_run.status_ended",
  "id": "sevt_01ghi...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "result": { "type": "completed" },
  "processed_at": "2026-10-09T14:09:12Z"
}
```

## I thread di un'esecuzione

Ogni agente in un'esecuzione lavora nel proprio [thread di sessione](https://platform.claude.com/docs/it/managed-agents/session-threads), che il server crea quando il workflow ne ha bisogno. Puoi elencare, leggere e seguire in streaming i thread di un'esecuzione come qualsiasi thread figlio, e rispondere alle loro chiamate agli strumenti dallo stream principale. Per fermarli, chiedi all'agente di fermare l'esecuzione (consulta [Interrompere una sessione con esecuzioni aperte](https://platform.claude.com/docs/it/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).

* **Raggruppamento:** Un thread di un'esecuzione ha il `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) dell'esecuzione, così come l'evento `session.thread_created` che lo annuncia. Gli altri thread, e gli eventi `session.thread_created` che li annunciano, hanno `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) impostato su `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`).
* **Agente:** `agent` (csharp, go: `Agent`) mostra l'agente eseguito dal thread. Per un agente che hai elencato nella [lista `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) di `workflows` (csharp, go: `Workflows`)](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) in `multiagent` (csharp, go: `Multiagent`), `agent` (csharp, go: `Agent`) contiene l'`id` (csharp, go: `ID`) e la `version` (csharp, go: `Version`) di quell'agente, come nel thread di un subagente che hai elencato. Per un agente definito dal workflow (un agente inline), `agent` (csharp, go: `Agent`) ha `type` `inline` e nessun `id` (csharp, go: `ID`) o `version` (csharp, go: `Version`). Ha il prompt di sistema scritto dal workflow, non quello dell'agente della sessione. Ha anche il nome e la descrizione che il workflow gli ha dato. Il server assegna un nome se il workflow non ne ha fornito uno. Usa il modello dell'agente della sessione, ovvero l'agente eseguito dalla sessione. I suoi strumenti, server MCP e skill sono un sottoinsieme di quelli dell'agente della sessione. Li riceve tutti, ma l'API non lo garantisce. I suoi strumenti mantengono le proprie policy di autorizzazione.
* **Cosa condividono i thread:** I thread di un'esecuzione lavorano nella sandbox della sessione, quindi ogni thread lavora con gli stessi file. Ciò include i file di un "memory store" (archivio di memoria) montato dalla sessione. Un agente definito dal workflow usa i propri server MCP con le credenziali che la sessione risolve per essi. Ogni thread ha la propria cronologia della conversazione.
* **Eventi:** Gli eventi `session.thread_created`, `session.thread_status_running`, `session.thread_status_idle` e `session.thread_status_terminated` di un thread di un'esecuzione arrivano anche sullo stream principale (consulta [Eventi dell'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#run-events)). I suoi eventi di messaggio restano sul suo stream. I suoi webhook di thread vengono inviati come per qualsiasi thread figlio. Per ciò che registra lo stream del thread stesso, consulta [Eventi dei thread di sessione](https://platform.claude.com/docs/it/managed-agents/session-threads#session-thread-events).
* **Fasi:** Nessun evento o campo indica in quale fase lavora un thread, e i thread di una stessa esecuzione possono avere lo stesso `agent_name`. Segui l'avanzamento di un'esecuzione tramite i suoi eventi di fase e distingui i suoi thread tramite `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`).
* **Archiviazione:** Il server archivia ogni thread al più tardi alla fine della sua esecuzione. Può archiviarne uno prima, una volta che il thread restituisce il proprio risultato o che l'esecuzione non ne ha più bisogno. Se a quel punto il thread è ancora in esecuzione o in attesa del tuo client, il server prima lo ferma. Un thread archiviato resta nell'elenco dei thread, con stato `terminated`. Non è necessario che tu archivi i thread di un'esecuzione.
* **Strumenti:** Un'esecuzione può creare più di un thread per lo stesso lavoro, quindi rendi gli strumenti chiamati dai tuoi agenti sicuri da chiamare due volte.

<Tip>
  Puoi chiedere all'agente il workflow che ha scritto per la tua richiesta. Attendi che l'esecuzione sia terminata e che la sessione sia `idle`. Quindi invia un `user.message` che chieda all'agente di stampare parola per parola il workflow con cui ha avviato l'esecuzione, e di non avviare un'altra esecuzione.

  ```text wrap
  Print the workflow that you started the run with, word for word, in one code block. Do not start another run.
  ```
</Tip>

## Sapere quando il lavoro è terminato

Mentre un'esecuzione è in corso, aspettati che la sessione rimanga `running`, anche quando nessuno dei suoi thread sta lavorando. Passa a `idle` con `requires_action` quando nessun thread sta lavorando e un thread attende il tuo client. Uno stato di inattività di per sé non significa che il lavoro sia terminato. Il lavoro è terminato quando entrambe le condizioni sono vere:

1. Ogni esecuzione di cui hai visto la creazione ha il suo `workflow_run.status_ended`.
2. Dopo di ciò, arriva un `session.status_idle` con `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) `end_turn`, e non è stato causato da una tua richiesta, come un'interruzione. Dopo un'interruzione, considera solo uno stato di inattività che arriva dopo il tuo successivo `user.message` o `user.define_outcome`.

* **Esecuzioni in pausa:** Un'esecuzione in pausa non mantiene la sessione `running`, quindi la sessione può diventare inattiva mentre l'esecuzione è ancora aperta. Al raggiungimento del budget, ad esempio, la sessione diventa inattiva con `budget_reached`. Il lavoro non è terminato finché l'esecuzione non termina.
* **Un'altra esecuzione:** L'agente può avviare una nuova esecuzione quando legge un risultato, quindi controlla di nuovo.
* **Esiti:** Se hai [definito un esito](https://platform.claude.com/docs/it/managed-agents/define-outcomes), nessuna valutazione inizia mentre un'esecuzione è aperta, che sia in corso o inattiva. Il turno in cui l'agente legge il risultato dell'esecuzione può avviarne una.
* **`retries_exhausted`:** Il turno dell'agente non è riuscito a causa di un errore: i tentativi sono esauriti, oppure l'errore non può essere ritentato, come un errore di fatturazione. Un'esecuzione potrebbe essere ancora in corso quando arriva questo stato di inattività. Se un'esecuzione è terminata e l'agente non ne ha ancora letto il risultato, il server avvia un nuovo turno senza alcun input da parte tua. La sessione torna `running`, quindi attendi il successivo stato di inattività. Se la sessione resta inattiva, leggi il `session.error` che lo ha preceduto e correggi la causa. Poi invia un `user.message`, oppure leggi tu stesso il `result` (csharp, go: `Result`) di ciascuna esecuzione.

## Seguire un'esecuzione

Questo esempio segue una sessione dal tuo messaggio alla risposta dell'agente. Apre lo stream e invia il messaggio. Quindi fa quanto segue:

* **Tiene traccia di ogni esecuzione** dal suo `workflow_run.created` al suo `workflow_run.status_ended`, e stampa ogni fase quando inizia.
* **Risponde alle chiamate agli strumenti personalizzati** all'arrivo di ciascun `agent.custom_tool_use`, perché un thread di un'esecuzione può attendere il tuo client mentre la sessione resta `running`. Se gli strumenti del tuo agente [richiedono una conferma](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#tool-confirmation), aggiungi un ramo che risponda a ogni `agent.tool_use` o `agent.mcp_tool_use` il cui `evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`) è `ask`. L'esempio non ne ha, perché un ramo che consente ogni chiamata trasformerebbe `always_ask` in "consenti sempre".
* **Si ferma** quando il [lavoro è terminato](https://platform.claude.com/docs/it/managed-agents/workflow-runs#know-when-the-work-is-done): nessuna esecuzione è aperta e la sessione diventa inattiva con `end_turn`. Si ferma anche se la sessione termina. In caso di stato di inattività con qualsiasi altro motivo di arresto tranne `requires_action`, come `budget_reached`, `retries_exhausted` o `refusal`, stampa il motivo e si ferma, quindi gestisci questi casi nel tuo codice. Si ferma su `retries_exhausted` anche quando il server sta per avviare un nuovo turno da solo. Continua ad attendere su `requires_action`, e su `end_turn` mentre un'esecuzione è aperta.

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Questo flusso di lavoro richiede più logica di un singolo comando shell. Usa il [Claude SDK](https://platform.claude.com/docs/it/cli-sdks-libraries/overview) per eseguirlo.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Questo flusso di lavoro richiede più logica di un singolo comando shell. Usa il [Claude SDK](https://platform.claude.com/docs/it/cli-sdks-libraries/overview) per eseguirlo.
  </CodeGroupItem>

  ```python Python
  open_runs: dict[str, str] = {}  # workflow_run_id -> run name
  phase_names: dict[tuple[str, str], str] = {}  # (run ID, phase ID) -> phase name

  # Apri prima lo stream, poi invia il messaggio dell'utente
  with client.beta.sessions.events.stream(session_id) as stream:
      client.beta.sessions.events.send(
          session_id,
          events=[
              {
                  "type": "user.message",
                  "content": [
                      {
                          "type": "text",
                          "text": "Which contracts in /contracts have a change-of-control clause?",
                      },
                  ],
              },
          ],
      )

      for event in stream:
          match event.type:
              case "workflow_run.created":
                  open_runs[event.workflow_run_id] = event.name
                  for phase in event.phases:
                      phase_names[event.workflow_run_id, phase.id] = phase.name
                  print(f"Run started: {event.name}")
              case "workflow_run.phase_started":
                  phase_id = event.workflow_run_phase_id
                  key = (event.workflow_run_id, phase_id)
                  print(f"  Phase: {phase_names.get(key, phase_id)}")
              case "workflow_run.status_ended":
                  name = open_runs.pop(event.workflow_run_id, event.workflow_run_id)
                  print(f"Run ended: {name} ({event.result.type})")
              case "agent.custom_tool_use":
                  # Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
                  # client mentre la sessione resta in esecuzione.
                  result = call_tool(event.name, event.input)
                  try:
                      client.beta.sessions.events.send(
                          session_id,
                          events=[
                              {
                                  "type": "user.custom_tool_result",
                                  "custom_tool_use_id": event.id,
                                  "content": [{"type": "text", "text": result}],
                              },
                          ],
                      )
                  except anthropic.BadRequestError as error:
                      # Il server rifiuta un risultato che arriva troppo tardi, dopo che
                      # ha archiviato il thread della chiamata. Continua a seguire l'esecuzione.
                      print(f"  Answer to {event.name} refused: {error.message}")
              case "session.status_idle":
                  # Finito quando ogni esecuzione è terminata e l'agente ha concluso il suo turno
                  if not open_runs and event.stop_reason.type == "end_turn":
                      break
                  # Un idle con requires_action attende il tuo client, quindi continua a leggere.
                  # Per qualsiasi altro motivo di arresto, stampalo e fermati.
                  if event.stop_reason.type not in ("end_turn", "requires_action"):
                      print(f"Session idle: {event.stop_reason.type}")
                      break
              case "session.status_terminated":
                  break
  ```

  ```typescript TypeScript
  const openRuns = new Map<string, string>(); // workflow_run_id -> run name
  const phaseNames = new Map<string, string>(); // "run ID:phase ID" -> phase name

  // Apri prima lo stream, poi invia il messaggio dell'utente
  const stream = await client.beta.sessions.events.stream(sessionId);
  await client.beta.sessions.events.send(sessionId, {
    events: [
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Which contracts in /contracts have a change-of-control clause?"
          }
        ]
      }
    ]
  });

  events: for await (const event of stream) {
    switch (event.type) {
      case "workflow_run.created":
        openRuns.set(event.workflow_run_id, event.name);
        for (const phase of event.phases) {
          phaseNames.set(`${event.workflow_run_id}:${phase.id}`, phase.name);
        }
        console.log(`Run started: ${event.name}`);
        break;
      case "workflow_run.phase_started": {
        const phaseId = event.workflow_run_phase_id;
        const phaseName = phaseNames.get(`${event.workflow_run_id}:${phaseId}`);
        console.log(`  Phase: ${phaseName ?? phaseId}`);
        break;
      }
      case "workflow_run.status_ended": {
        const name = openRuns.get(event.workflow_run_id) ?? event.workflow_run_id;
        openRuns.delete(event.workflow_run_id);
        console.log(`Run ended: ${name} (${event.result.type})`);
        break;
      }
      case "agent.custom_tool_use": {
        // Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
        // client mentre la sessione resta in esecuzione.
        const result = await callTool(event.name, event.input);
        try {
          await client.beta.sessions.events.send(sessionId, {
            events: [
              {
                type: "user.custom_tool_result",
                custom_tool_use_id: event.id,
                content: [{ type: "text", text: result }]
              }
            ]
          });
        } catch (error) {
          // Il server rifiuta un risultato che arriva troppo tardi, dopo che ha
          // archiviato il thread della chiamata. Continua a seguire l'esecuzione.
          if (!(error instanceof Anthropic.BadRequestError)) {
            throw error;
          }
          console.log(`  Answer to ${event.name} refused: ${error.message}`);
        }
        break;
      }
      case "session.status_idle": {
        // Terminato quando ogni esecuzione è finita e l'agente ha completato il suo turno
        const reason = event.stop_reason.type;
        if (openRuns.size === 0 && reason === "end_turn") {
          break events;
        }
        // Uno stato idle con requires_action attende il tuo client, quindi continua a leggere.
        // Per qualsiasi altro motivo di arresto, stampalo e fermati.
        if (reason !== "end_turn" && reason !== "requires_action") {
          console.log(`Session idle: ${reason}`);
          break events;
        }
        break;
      }
      case "session.status_terminated":
        break events;
    }
  }
  ```

  ```csharp C#
  var openRuns = new Dictionary<string, string>(); // workflow_run_id -> run name
  var phaseNames = new Dictionary<(string, string), string>(); // (run ID, phase ID) -> phase name

  // Apri prima lo stream, poi invia il messaggio dell'utente. La chiamata raw-response
  // apre subito lo stream. La chiamata semplice attenderebbe la prima lettura.
  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(sessionId);
  await client.Beta.Sessions.Events.Send(sessionId, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Which contracts in /contracts have a change-of-control clause?",
                  },
              ],
          },
      ],
  });

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.Value is BetaManagedAgentsWorkflowRunCreatedEvent created)
      {
          openRuns[created.WorkflowRunID] = created.Name;
          foreach (var listed in created.Phases)
          {
              phaseNames[(created.WorkflowRunID, listed.ID)] = listed.Name;
          }
          Console.WriteLine($"Run started: {created.Name}");
      }
      else if (streamEvent.Value is BetaManagedAgentsWorkflowRunPhaseStartedEvent phase)
      {
          var phaseId = phase.WorkflowRunPhaseID;
          var key = (phase.WorkflowRunID, phaseId);
          Console.WriteLine($"  Phase: {phaseNames.GetValueOrDefault(key, phaseId)}");
      }
      else if (streamEvent.Value is BetaManagedAgentsWorkflowRunStatusEndedEvent ended)
      {
          var name = openRuns.GetValueOrDefault(ended.WorkflowRunID, ended.WorkflowRunID);
          openRuns.Remove(ended.WorkflowRunID);
          var outcome = ended.Result.Value switch
          {
              BetaManagedAgentsWorkflowRunResultCompleted => "completed",
              BetaManagedAgentsWorkflowRunResultStopped => "stopped",
              BetaManagedAgentsWorkflowRunResultError => "error",
              _ => "ended",
          };
          Console.WriteLine($"Run ended: {name} ({outcome})");
      }
      else if (streamEvent.Value is BetaManagedAgentsAgentCustomToolUseEvent toolUse)
      {
          // Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
          // client mentre la sessione resta in esecuzione.
          var result = await CallTool(toolUse.Name, toolUse.Input);
          try
          {
              await client.Beta.Sessions.Events.Send(sessionId, new()
              {
                  Events =
                  [
                      new BetaManagedAgentsUserCustomToolResultEventParams
                      {
                          Type = BetaManagedAgentsUserCustomToolResultEventParamsType.UserCustomToolResult,
                          CustomToolUseID = toolUse.ID,
                          Content =
                          [
                              new BetaManagedAgentsTextBlock
                              {
                                  Type = BetaManagedAgentsTextBlockType.Text,
                                  Text = result,
                              },
                          ],
                      },
                  ],
              });
          }
          catch (AnthropicBadRequestException error)
          {
              // Il server rifiuta un risultato che arriva troppo tardi, dopo che
              // ha archiviato il thread della chiamata. Continua a seguire l'esecuzione.
              Console.WriteLine($"  Answer to {toolUse.Name} refused: {error.Message}");
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent idle)
      {
          // Finito quando ogni esecuzione è terminata e l'agente ha concluso il suo turno
          var finished = idle.StopReason?.Value is BetaManagedAgentsSessionEndTurn;
          if (openRuns.Count == 0 && finished)
          {
              break;
          }
          // Un idle con requires_action attende il tuo client, quindi continua a leggere.
          // Per qualsiasi altro motivo di arresto, stampalo e fermati.
          if (!finished && idle.StopReason?.Value is not BetaManagedAgentsSessionRequiresAction)
          {
              var reason = idle.StopReason?.Json.GetProperty("type").GetString();
              Console.WriteLine($"Session idle: {reason}");
              break;
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusTerminatedEvent)
      {
          break;
      }
  }
  ```

  ```go Go
  	openRuns := map[string]string{}      // workflow_run_id -> run name
  	phaseNames := map[[2]string]string{} // {run ID, phase ID} -> phase name

  	// Apri prima lo stream, poi invia il messaggio dell'utente
  	stream := client.Beta.Sessions.Events.StreamEvents(ctx, sessionID, anthropic.BetaSessionEventStreamParams{})
  	defer stream.Close()

  	if _, err := client.Beta.Sessions.Events.Send(ctx, sessionID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  						Text: "Which contracts in /contracts have a change-of-control clause?",
  					},
  				}},
  			},
  		}},
  	}); err != nil {
  		panic(err)
  	}

  events:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsWorkflowRunCreatedEvent:
  			openRuns[event.WorkflowRunID] = event.Name
  			for _, phase := range event.Phases {
  				phaseNames[[2]string{event.WorkflowRunID, phase.ID}] = phase.Name
  			}
  			fmt.Printf("Run started: %s\n", event.Name)
  		case anthropic.BetaManagedAgentsWorkflowRunPhaseStartedEvent:
  			phaseName, ok := phaseNames[[2]string{event.WorkflowRunID, event.WorkflowRunPhaseID}]
  			if !ok {
  				phaseName = event.WorkflowRunPhaseID
  			}
  			fmt.Printf("  Phase: %s\n", phaseName)
  		case anthropic.BetaManagedAgentsWorkflowRunStatusEndedEvent:
  			name, ok := openRuns[event.WorkflowRunID]
  			if !ok {
  				name = event.WorkflowRunID
  			}
  			delete(openRuns, event.WorkflowRunID)
  			fmt.Printf("Run ended: %s (%s)\n", name, event.Result.Type)
  		case anthropic.BetaManagedAgentsAgentCustomToolUseEvent:
  			// Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
  			// client mentre la sessione resta in esecuzione.
  			result := callTool(event.Name, event.Input)
  			if _, err := client.Beta.Sessions.Events.Send(ctx, sessionID, anthropic.BetaSessionEventSendParams{
  				Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  					OfUserCustomToolResult: &anthropic.BetaManagedAgentsUserCustomToolResultEventParams{
  						Type:            anthropic.BetaManagedAgentsUserCustomToolResultEventParamsTypeUserCustomToolResult,
  						CustomToolUseID: event.ID,
  						Content: []anthropic.BetaManagedAgentsUserCustomToolResultEventParamsContentUnion{{
  							OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  								Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  								Text: result,
  							},
  						}},
  					},
  				}},
  			}); err != nil {
  				// Il server rifiuta un risultato che arriva troppo tardi, dopo che ha
  				// archiviato il thread della chiamata. Continua a seguire l'esecuzione.
  				var apiErr *anthropic.Error
  				if !errors.As(err, &apiErr) || apiErr.StatusCode != http.StatusBadRequest {
  					panic(err)
  				}
  				fmt.Printf("  Answer to %s refused: %v\n", event.Name, err)
  			}
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			// Terminato quando ogni esecuzione è finita e l'agente ha completato il suo turno
  			switch event.StopReason.AsAny().(type) {
  			case anthropic.BetaManagedAgentsSessionEndTurn:
  				if len(openRuns) == 0 {
  					break events
  				}
  			// Uno stato idle con requires_action attende il tuo client, quindi continua a leggere.
  			// Per qualsiasi altro motivo di arresto, stampalo e fermati.
  			case anthropic.BetaManagedAgentsSessionRequiresAction:
  			default:
  				fmt.Printf("Session idle: %s\n", event.StopReason.Type)
  				break events
  			}
  		case anthropic.BetaManagedAgentsSessionStatusTerminatedEvent:
  			break events
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  var openRuns = new HashMap<String, String>(); // workflow_run_id -> run name
  var phaseNames = new HashMap<String, String>(); // "run ID:phase ID" -> phase name

  // Apri prima lo stream, poi invia il messaggio dell'utente
  try (var stream = client.beta().sessions().events().streamStreaming(sessionId)) {
      client.beta().sessions().events().send(
          sessionId,
          EventSendParams.builder()
              .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                  .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
                  .addTextContent("Which contracts in /contracts have a change-of-control clause?")
                  .build())
              .build()
      );

      Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
      events:
      for (var event : events) {
          switch (event.type().value()) {
              case WORKFLOW_RUN_CREATED -> {
                  var created = event.asWorkflowRunCreated();
                  openRuns.put(created.workflowRunId(), created.name());
                  created.phases().forEach(phase ->
                      phaseNames.put(created.workflowRunId() + ":" + phase.id(), phase.name()));
                  IO.println("Run started: " + created.name());
              }
              case WORKFLOW_RUN_PHASE_STARTED -> {
                  var started = event.asWorkflowRunPhaseStarted();
                  var phaseId = started.workflowRunPhaseId();
                  var key = started.workflowRunId() + ":" + phaseId;
                  IO.println("  Phase: " + phaseNames.getOrDefault(key, phaseId));
              }
              case WORKFLOW_RUN_STATUS_ENDED -> {
                  var ended = event.asWorkflowRunStatusEnded();
                  var name = openRuns.getOrDefault(ended.workflowRunId(), ended.workflowRunId());
                  openRuns.remove(ended.workflowRunId());
                  var result = ended.result();
                  var outcome = result.isCompleted() ? "completed"
                      : result.isStopped() ? "stopped"
                      : result.isError() ? "error"
                      : "ended";
                  IO.println("Run ended: " + name + " (" + outcome + ")");
              }
              case AGENT_CUSTOM_TOOL_USE -> {
                  // Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
                  // client mentre la sessione resta in esecuzione.
                  var toolUse = event.asAgentCustomToolUse();
                  var result = callTool(toolUse.name(), toolUse.input());
                  try {
                      client.beta().sessions().events().send(
                          sessionId,
                          EventSendParams.builder()
                              .addEvent(BetaManagedAgentsUserCustomToolResultEventParams.builder()
                                  .type(BetaManagedAgentsUserCustomToolResultEventParams.Type.USER_CUSTOM_TOOL_RESULT)
                                  .customToolUseId(toolUse.id())
                                  .addTextContent(result)
                                  .build())
                              .build());
                  } catch (BadRequestException e) {
                      // Il server rifiuta un risultato che arriva troppo tardi, dopo che
                      // ha archiviato il thread della chiamata. Continua a seguire l'esecuzione.
                      IO.println("  Answer to " + toolUse.name() + " refused: " + e.getMessage());
                  }
              }
              case SESSION_STATUS_IDLE -> {
                  // Finito quando ogni esecuzione è terminata e l'agente ha concluso il suo turno
                  var stopReason = event.asSessionStatusIdle().stopReason();
                  if (openRuns.isEmpty() && stopReason.isEndTurn()) {
                      break events;
                  }
                  // Uno stato idle con requires_action attende il tuo client, quindi continua a leggere.
                  // Per qualsiasi altro motivo di arresto, stampalo e fermati.
                  if (!stopReason.isEndTurn() && !stopReason.isRequiresAction()) {
                      IO.println("Session idle: " + stopReason.type().asString());
                      break events;
                  }
              }
              case SESSION_STATUS_TERMINATED -> {
                  break events;
              }
              default -> {}
          }
      }
  }
  ```

  ```php PHP
  $openRuns = []; // workflow_run_id => run name
  $phaseNames = []; // run ID => [phase ID => phase name]

  // Apri prima lo stream, poi invia il messaggio dell'utente
  $stream = $client->beta->sessions->events->streamStream($sessionId);
  $client->beta->sessions->events->send(
      $sessionId,
      events: [
          [
              'type' => 'user.message',
              'content' => [
                  ['type' => 'text', 'text' => 'Which contracts in /contracts have a change-of-control clause?'],
              ],
          ],
      ],
  );

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunCreatedEvent:
              $openRuns[$event->workflowRunID] = $event->name;
              foreach ($event->phases as $phase) {
                  $phaseNames[$event->workflowRunID][$phase->id] = $phase->name;
              }
              echo "Run started: {$event->name}", PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunPhaseStartedEvent:
              $phaseId = $event->workflowRunPhaseID;
              echo '  Phase: ', $phaseNames[$event->workflowRunID][$phaseId] ?? $phaseId, PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunStatusEndedEvent:
              $name = $openRuns[$event->workflowRunID] ?? $event->workflowRunID;
              unset($openRuns[$event->workflowRunID]);
              echo "Run ended: {$name} ({$event->result->type})", PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentCustomToolUseEvent:
              // Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
              // client mentre la sessione resta in esecuzione.
              $result = callTool($event->name, $event->input);
              try {
                  $client->beta->sessions->events->send(
                      $sessionId,
                      events: [
                          [
                              'type' => 'user.custom_tool_result',
                              'custom_tool_use_id' => $event->id,
                              'content' => [['type' => 'text', 'text' => $result]],
                          ],
                      ],
                  );
              } catch (\Anthropic\Core\Exceptions\BadRequestException $error) {
                  // Il server rifiuta un risultato che arriva troppo tardi, dopo che
                  // ha archiviato il thread della chiamata. Continua a seguire l'esecuzione.
                  echo "  Answer to {$event->name} refused: {$error->getMessage()}", PHP_EOL;
              }
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent:
              // Terminato quando ogni esecuzione è finita e l'agente ha completato il suo turno
              $finished = $event->stopReason->type === 'end_turn';
              if (!$openRuns && $finished) {
                  break 2;
              }
              // Uno stato idle con requires_action attende il tuo client, quindi continua a leggere.
              // Per qualsiasi altro motivo di arresto, stampalo e fermati.
              if (!$finished && $event->stopReason->type !== 'requires_action') {
                  echo "Session idle: {$event->stopReason->type}", PHP_EOL;
                  break 2;
              }
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusTerminatedEvent:
              break 2;
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  open_runs = {} # workflow_run_id => run name
  phase_names = {} # [run ID, phase ID] => phase name

  # Apri prima lo stream, poi invia il messaggio dell'utente
  stream = client.beta.sessions.events.stream_events(session_id)

  client.beta.sessions.events.send_(
    session_id,
    events: [{
      type: "user.message",
      content: [{type: "text", text: "Which contracts in /contracts have a change-of-control clause?"}]
    }]
  )

  stream.each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunCreatedEvent
      open_runs[event.workflow_run_id] = event.name
      event.phases.each { |phase| phase_names[[event.workflow_run_id, phase.id]] = phase.name }
      puts "Run started: #{event.name}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunPhaseStartedEvent
      phase_id = event.workflow_run_phase_id
      puts "  Phase: #{phase_names.fetch([event.workflow_run_id, phase_id], phase_id)}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunStatusEndedEvent
      name = open_runs.delete(event.workflow_run_id) || event.workflow_run_id
      puts "Run ended: #{name} (#{event.result.type})"
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentCustomToolUseEvent
      # Rispondi quando arriva l'evento. Il thread di un'esecuzione può attendere il tuo
      # client mentre la sessione resta in esecuzione.
      result = call_tool.call(event.name, event.input)
      begin
        client.beta.sessions.events.send_(
          session_id,
          events: [{
            type: "user.custom_tool_result",
            custom_tool_use_id: event.id,
            content: [{type: "text", text: result}]
          }]
        )
      rescue Anthropic::Errors::BadRequestError => error
        # Il server rifiuta un risultato che arriva troppo tardi, dopo aver archiviato
        # il thread della chiamata. Continua a seguire l'esecuzione.
        puts "  Answer to #{event.name} refused: #{error.message}"
      end
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      reason = event.stop_reason.type.to_sym
      # Finito quando ogni esecuzione è terminata e l'agente ha completato il suo turno
      break if open_runs.empty? && reason == :end_turn
      # Uno stato idle con requires_action attende il tuo client, quindi continua a leggere.
      # Per qualsiasi altro motivo di arresto, stampalo e fermati.
      unless %i[end_turn requires_action].include?(reason)
        puts "Session idle: #{reason}"
        break
      end
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusTerminatedEvent
      break
    end
  end
  ```
</CodeGroup>

## Interrompere una sessione con esecuzioni aperte

Invia [`user.interrupt`](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#interrupt-the-agent) senza `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), oppure con l'ID del thread principale. Ferma il turno dell'agente. Non termina alcuna esecuzione. Le esecuzioni della sessione potrebbero mettersi in pausa o continuare, e i loro eventi potrebbero non indicare quale delle due. La durata di un'esecuzione in pausa continua a scorrere, quindi l'esecuzione può terminare con `timeout_error` mentre è in pausa.

* **Chiamate agli strumenti in attesa:** Dopo l'interruzione, una chiamata a uno strumento di un thread dell'esecuzione potrebbe ancora attendere il tuo client. Rispondi a ciascuna. Per annullare una chiamata che richiede conferma, negala. Per annullare una chiamata a uno strumento personalizzato, invia un risultato con `is_error` (java, php: `isError`; csharp, go: `IsError`) impostato su `true` e un testo in `content` (csharp, go: `Content`) che ne spieghi il motivo. Mentre la sessione è `idle` con `requires_action`, un `user.message` restituisce 400, quindi rispondi prima alle chiamate.
* **Per fermare le esecuzioni:** Invia un `user.message` chiedendo all'agente di fermare le sue esecuzioni. Un'esecuzione fermata termina con `result` `{"type": "stopped"}`. Mentre la sessione è `idle` con `budget_reached`, un `user.message` restituisce 400 finché non aumenti o rimuovi il budget. Aumentarlo o rimuoverlo riprende anche le esecuzioni che il budget aveva messo in pausa, a meno che non le abbia messe in pausa anche l'interruzione.
* **Per continuare:** Invia un `user.message` chiedendo all'agente di continuare le sue esecuzioni. Dopo un'interruzione, le esecuzioni potrebbero attendere questo messaggio. Se la sessione è `idle` con `budget_reached`, aumenta o rimuovi prima il budget.
* **Risultati delle esecuzioni:** Un'esecuzione che termina dopo l'interruzione invia comunque `workflow_run.status_ended`.

## Mentre un'esecuzione è aperta

| Richiesta                                                                                             | Mentre un'esecuzione è aperta                                                                                                                                                                                                                                                                                                                        | Cosa fare                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Archiviare o eliminare la sessione                                                                    | Potrebbe restituire 400 mentre un'esecuzione è aperta, qualunque sia lo stato della sessione. L'`error.details.error_code` dell'errore può essere `"workflow_run_open"`. Potrebbe anche riuscire.                                                                                                                                                    | Chiedi all'agente di fermare le sue esecuzioni, oppure attendi che ogni esecuzione sia terminata. Un'esecuzione in pausa termina da sola soltanto quando la sua durata massima scade. Quindi invia la richiesta una volta che la sessione è `idle`. Un'archiviazione riuscita termina ogni esecuzione aperta con `{"type": "stopped"}`. Dopo un'archiviazione, il `workflow_run.status_ended` di un'esecuzione, e il `workflow_run.phase_ended` di una fase ancora aperta, non arrivano sullo stream. Elenca gli eventi della sessione per leggerli. Dopo un'eliminazione riuscita, nessun evento `workflow_run` segnala la fine delle esecuzioni della sessione.                                                                                                                                                                                                                                                                                                                                                                   |
| Archiviare uno dei thread di un'esecuzione                                                            | Restituisce 400 con `error.details.error_code: "workflow_run_open"` mentre l'esecuzione è aperta, in corso o inattiva, a meno che il server non abbia già archiviato il thread.                                                                                                                                                                      | Niente. Il server archivia i thread di un'esecuzione.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| Aggiornare l'`agent` (csharp, go: `Agent`) della sessione                                             | Restituisce 400 con `error.details.error_code: "workflow_run_open"` mentre una qualsiasi esecuzione è aperta, anche se in pausa. L'aggiornamento dell'agente sottostante è comunque accettato, e la sessione mantiene la propria copia. Una richiesta che invia anche altri campi, come `budget` (csharp, go: `Budget`), viene rifiutata per intero. | Attendi che ogni esecuzione abbia il suo `workflow_run.status_ended`, oppure chiedi all'agente di fermare le sue esecuzioni.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Rispondere a una chiamata a uno strumento o a una conferma di strumento da un thread di un'esecuzione | Consentito. Arriva sullo stream principale, e il suo `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) indica il thread.                                                                                                                                                                          | Rispondi non appena arriva l'evento, passando l'`id` (csharp, go: `ID`) dell'evento come `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) o `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`). Non attendere `session.status_idle`: la sessione può restare `running` mentre gli altri thread dell'esecuzione lavorano. Una volta che il server ha archiviato il thread, un risultato di strumento per una delle sue chiamate non ha alcun effetto e può restituire 400. Quando un risultato di strumento restituisce 400, trova il thread della chiamata nell'elenco dei thread. Se il suo stato è `terminated`, il risultato è arrivato troppo tardi, quindi scartalo. Invia ogni risultato di strumento in una richiesta separata, perché il server rifiuta un'intera richiesta quando ne rifiuta uno degli eventi. Una conferma di strumento che arriva troppo tardi restituisce 200, il che non significa che lo strumento sia stato eseguito. |

### Ricostruire lo stato delle esecuzioni dopo la riconnessione

Ricostruisci lo stato di ogni esecuzione a partire dagli eventi della sessione. Lo stream non riproduce ciò che ti sei perso: una nuova connessione consegna solo gli eventi emessi dopo la sua apertura. Quindi elenca gli eventi con un filtro `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`), con una voce per ogni tipo di evento, come in [Elencare gli eventi passati](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#list-past-events). Passa il `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) di ogni risposta come `page` (cli: `--page`; csharp, go: `Page`) finché `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) non è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) o assente. `workflow_run.created`, `workflow_run.status_running`, `workflow_run.status_idle` e `workflow_run.status_ended` forniscono lo stato di ogni esecuzione, con l'eccezione che un'esecuzione messa in pausa dopo un'interruzione potrebbe ancora risultare in corso. `workflow_run.phase_started` e `workflow_run.phase_ended` ricostruiscono l'avanzamento. Un'esecuzione senza ancora alcun evento di stato non ha iniziato a essere eseguita. Nessun endpoint elenca le esecuzioni.

## Costi e budget

Le richieste al modello di un'esecuzione contano ai fini del [budget della sessione](https://platform.claude.com/docs/it/managed-agents/budgets). Un'esecuzione non ha un prezzo proprio. I token usati dai suoi agenti vengono fatturati come gli altri token della sessione, alle tariffe di ciascun modello. Per tutti gli addebiti di una sessione, consulta [Prezzi di Claude Managed Agents](https://platform.claude.com/docs/it/about-claude/pricing#claude-managed-agents-pricing).

* **Utilizzo di una singola esecuzione:** Elenca i thread della sessione e somma i conteggi dei token in `usage` (csharp, go: `Usage`) dei thread con il `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) dell'esecuzione. L'elenco include i thread archiviati, il cui stato è `terminated`, quindi i thread di un'esecuzione terminata vengono conteggiati. Passa il `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) di ogni risposta come `page` (cli: `--page`; csharp, go: `Page`) finché `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) non è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) o assente, e salta i thread privi di `usage` (csharp, go: `Usage`). Se invece sommi il `list_cost` (java, php: `listCost`; csharp, go: `ListCost`) dei thread, il totale esclude il tempo di esecuzione della sessione e ogni valore viene arrotondato separatamente.
* **Al raggiungimento del budget:** Ogni esecuzione aperta va in pausa e la sessione riporta `idle` con `budget_reached`, oppure `requires_action` se è in attesa anche una chiamata a uno strumento. Ogni thread completa la richiesta al modello già avviata, quindi un'esecuzione può superare il budget di una richiesta per ogni thread attivo. Aumentare o rimuovere il budget riprende le esecuzioni che ha messo in pausa, a meno che non siano state messe in pausa anche da un'interruzione. Se l'utilizzo della sessione include un modello senza prezzo di listino, solo la rimozione del budget le riprende; consulta [Modelli senza prezzo di listino](https://platform.claude.com/docs/it/managed-agents/budgets#models-without-a-list-price). La durata di un'esecuzione in pausa continua a scorrere, quindi l'esecuzione può terminare con `timeout_error` mentre è in pausa.

## Limiti

| Limite                                                          | Valore                                                                 | Al raggiungimento del limite                                                                                                                                                                                                                               |
| --------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Thread attivi contemporaneamente in un'esecuzione               | 64                                                                     | L'esecuzione non ne crea altri finché uno non termina. L'API non garantisce questo numero.                                                                                                                                                                 |
| Agenti che un workflow avvia nell'intera durata dell'esecuzione | 1.000                                                                  | Quando il workflow ne richiede di più, il server non avvia un altro agente e l'esecuzione termina con `thread_limit_error`. Il server può eseguire di nuovo un agente fallito su un nuovo thread, quindi un'esecuzione potrebbe avere più di 1.000 thread. |
| Durata massima dell'esecuzione                                  | 24 ore per impostazione predefinita, o la durata impostata dall'agente | L'esecuzione termina con `timeout_error`. Nessun evento indica quale durata ha impostato l'agente.                                                                                                                                                         |
| Esecuzioni aperte contemporaneamente in una sessione            | 10 per impostazione predefinita                                        | Il server rifiuta di avviare un'altra esecuzione. La chiamata allo strumento dell'agente riceve un errore, e tu ricevi un `workflow_run.error` il cui `error.type` è `max_workflow_runs_error`. Le esecuzioni inattive contano ai fini del limite.         |

Il server accorcia il `name` (csharp, go: `Name`) di un'esecuzione o di una fase a 64 caratteri e la sua `description` (csharp, go: `Description`) a 256. Il server ha altri limiti sui workflow, e regole per essi, che non sono elencati qui. Ciò che vedi dipende da quando il server rileva il problema:

| Cosa succede                                                                                        | Cosa vedi                                                                                |
| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Il workflow supera uno degli altri limiti quando l'agente avvia l'esecuzione                        | L'avvio viene rifiutato. Ricevi un `workflow_run.error` e nessuna esecuzione.            |
| L'esecuzione supera uno degli altri limiti in seguito                                               | Ricevi un `workflow_run.error`, e poi l'esecuzione può terminare con `unknown_error`.    |
| Il server rileva dopo l'avvio che il workflow viola una regola per i workflow, diversa da un limite | Ricevi un `workflow_run.error`, e l'esecuzione può quindi terminare con `program_error`. |

Una sessione può avviare un numero qualsiasi di esecuzioni nel corso della sua durata.

* **Avvio delle esecuzioni:** Solo l'agente sul thread principale della sessione avvia le esecuzioni. Un agente che lavora nel thread di un'esecuzione non può avviare un'esecuzione propria, quindi le esecuzioni non si annidano.
* **Terminazione delle esecuzioni:** Nessun evento che invii termina un'esecuzione; l'archiviazione della sessione può farlo.
* **Thread di un'esecuzione:** Non puoi [fermarne uno tramite il suo ID](https://platform.claude.com/docs/it/managed-agents/session-threads#interrupt-a-session-thread), né archiviarne uno mentre la sua esecuzione è aperta.
* **Limite dei thread:** I thread di un'esecuzione sono esenti dal [limite dei thread figli](https://platform.claude.com/docs/it/managed-agents/session-threads#primary-thread-and-session-threads) della sessione.
* **Visibilità:** Non vedi il codice del workflow, ma puoi chiedere il workflow all'agente, come descritto nel suggerimento in [I thread di un'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#a-runs-threads). Inoltre non vedi le chiamate agli strumenti che l'agente effettua per avviare e gestire le esecuzioni, né il risultato che ogni thread restituisce al workflow.

### Limiti di velocità

Il lavoro di un'esecuzione viene conteggiato nei "rate limit" (limiti di velocità) che la tua organizzazione ha già.

| Cosa                                                                                             | Conta ai fini di                                                                                                                                                              | Cosa fare                                                                                                                                                           |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Le richieste del tuo client per recuperare o elencare la sessione, i suoi thread e i loro eventi | Il limite di lettura per gli [endpoint di Managed Agents](https://platform.claude.com/docs/it/managed-agents/reference#rate-limits)                                           | Segui un'esecuzione sullo stream di eventi della sessione invece di effettuare polling.                                                                             |
| Le richieste al modello dai thread di un'esecuzione                                              | I tuoi [limiti di velocità della Messages API](https://platform.claude.com/docs/it/api/rate-limits) per il modello usato da ciascun thread, insieme al resto del tuo traffico | Lascia spazio per un'esecuzione in quei limiti, oppure [richiedi limiti più elevati](https://platform.claude.com/docs/it/api/rate-limits#requesting-higher-limits). |

Quando una richiesta al modello da uno dei thread di un'esecuzione è soggetta a limite di velocità, o il modello è sovraccarico, lo stream del thread stesso può ricevere un `session.error` di tipo `model_rate_limited_error` o `model_overloaded_error`:

* Se il suo `retry_status.type` è `retrying`, il server sta ritentando la richiesta e il thread sta ancora lavorando.
* Se è `exhausted`, il thread è fallito. Se il workflow lascia che quell'errore termini l'esecuzione, l'esecuzione termina con `program_error`, che non indica la causa. Leggi gli eventi dei thread falliti per trovarla.

Il server limita anche quanto possono fare ogni minuto tutte le sessioni della tua organizzazione. Un thread che raggiunge questo limite si ferma, con un `session.error` sul proprio stream il cui messaggio menziona un limite di velocità. Attendi un minuto prima di chiedere all'agente di continuare.
