---
title: Thread di sessione
url: https://platform.claude.com/docs/it/managed-agents/session-threads
description: Elenca, interrompi e archivia i thread di una sessione multiagente, leggi i loro eventi e gestisci le autorizzazioni degli strumenti tra di essi.
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

In una [sessione multiagente](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration), ogni agente lavora nel proprio **"session thread" (thread di sessione)**. Questa pagina spiega come elencare, interrompere e archiviare i thread, gli eventi che inviano e come funzionano le autorizzazioni degli strumenti tra di essi. Anche un'[esecuzione di workflow](https://platform.claude.com/docs/it/managed-agents/workflow-runs) crea thread di sessione.

## Thread principale e thread di sessione

Lo **stream di eventi a livello di sessione** (`/v1/sessions/{session_id}/events/stream`) è considerato il **"primary thread" (thread principale)** e contiene una vista condensata di tutta l'attività in tutti i thread. Non vedi l'attività completa dei [subagenti](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#delegate-to-subagents), ma vedi l'inizio e la fine del loro lavoro, oltre agli eventi bloccanti come le richieste di autorizzazione degli strumenti.

I **thread di sessione** sono il luogo in cui puoi approfondire l'attività di un agente specifico.

Lo `status` (csharp, go: `Status`) della sessione è un'aggregazione di tutta l'attività degli agenti; se almeno un thread è `running`, anche lo stato complessivo della sessione è `running`. Anche un'[esecuzione di workflow](https://platform.claude.com/docs/it/managed-agents/workflow-runs) in corso può mantenere la sessione `running`, anche quando nessuno dei suoi thread sta lavorando. Quando nessun thread sta lavorando e un thread attende il tuo client, la sessione è `idle`; consulta [Sapere quando il lavoro è terminato](https://platform.claude.com/docs/it/managed-agents/workflow-runs#know-when-the-work-is-done).

Un [budget di sessione](https://platform.claude.com/docs/it/managed-agents/budgets) è un unico limite condiviso tra tutti i thread di una sessione. Quando il limite viene raggiunto, i thread si mettono in pausa in modo indipendente e il costo di ciascun thread viene calcolato in base al modello servito per quel thread.

<Note>
  Una sessione può avere al massimo 25 thread figli alla volta. I thread inattivi vengono conteggiati finché non li archivi, mentre il thread principale non viene conteggiato. L'agente del thread principale può chiamare più copie di un singolo subagente, creando più thread associati a un unico `agent`. I thread di consultazione dell'[advisor](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#give-the-session-an-advisor) sono esenti da questo limite. Lo sono anche i thread di un'[esecuzione di workflow](https://platform.claude.com/docs/it/managed-agents/workflow-runs).
</Note>

## Elencare i thread

Elenca tutti i thread associati a una sessione come segue:

<CodeGroup>
  ```bash cURL
  curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01"
  ```

  ```bash CLI
  ant beta:sessions:threads list --session-id "$SESSION_ID"
  ```

  ```python Python
  for thread in client.beta.sessions.threads.list(session.id):
      agent = thread.agent
      label = agent.type if agent.type == "advisor" else agent.name
      print(f"[{label}] {thread.status}")
  ```

  ```typescript TypeScript
  for await (const thread of client.beta.sessions.threads.list(session.id)) {
    const label = thread.agent.type === "advisor" ? thread.agent.type : thread.agent.name;
    console.log(`[${label}] ${thread.status}`);
  }
  ```

  ```csharp C#
  await foreach (var sessionThread in (await client.Beta.Sessions.Threads.List(session.ID)).Paginate())
  {
      var label = sessionThread.Agent.Name ?? sessionThread.Agent.Json.GetProperty("type").GetString();
      Console.WriteLine($"[{label}] {sessionThread.Status.Raw()}");
  }
  ```

  ```go Go
  threads := client.Beta.Sessions.Threads.ListAutoPaging(ctx, session.ID, anthropic.BetaSessionThreadListParams{})
  for threads.Next() {
  	thread := threads.Current()
  	label := cmp.Or(thread.Agent.Name, thread.Agent.Type)
  	fmt.Printf("[%s] %s\n", label, thread.Status)
  }
  if err := threads.Err(); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  for (var thread : client.beta().sessions().threads().list(session.id()).autoPager()) {
      var agent = thread.agent();
      var label = agent.isAgent() ? agent.asAgent().name() : agent.type().asString();
      IO.println("[" + label + "] " + thread.status());
  }
  ```

  ```php PHP
  foreach ($client->beta->sessions->threads->list($session->id)->pagingEachItem() as $thread) {
      $label = $thread->agent instanceof \Anthropic\Beta\Agents\BetaManagedAgentsAdvisor
          ? $thread->agent->type
          : $thread->agent->name;
      echo "[{$label}] {$thread->status}\n";
  }
  ```

  ```ruby Ruby
  client.beta.sessions.threads.list(session.id).auto_paging_each do |thread|
    agent = thread.agent
    label = agent.type == :advisor ? agent.type : agent.name
    puts "[#{label}] #{thread.status}"
  end
  ```
</CodeGroup>

L'elenco completo include il thread principale. `parent_thread_id` (java: `parentThreadId`; php: `parentThreadID`; csharp, go: `ParentThreadID`) è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) per il thread principale. Ogni altro thread è un thread figlio. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) è `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) tranne che sui [thread di un'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#a-runs-threads).

Per elencare solo i thread con determinati stati, aggiungi `statuses[]` alla richiesta e ripetilo per indicare più di uno stato, come in `?statuses[]=running&statuses[]=idle`. Omettilo per restituire i thread di ogni stato.

## Interrompere un thread di sessione

Invia `user.interrupt` con `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) per fermare un thread specifico. Omettere `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) interrompe ogni thread non archiviato della sessione, incluso quello principale. In una sessione con workflow dinamici, un'interruzione non termina alcuna esecuzione, e un'interruzione che indica un thread di un'esecuzione non ferma nulla. Un'interruzione chiude le chiamate agli strumenti in sospeso degli altri thread figli, ma non fare affidamento su di essa per chiudere quelle di un thread di un'esecuzione. Consulta [Interrompere una sessione con esecuzioni aperte](https://platform.claude.com/docs/it/managed-agents/workflow-runs#interrupt-a-session-with-runs-open).

<CodeGroup>
  ```bash cURL
  curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{"events": [{"type": "user.interrupt", "session_thread_id": "'"$THREAD_ID"'"}]}'
  ```

  ```bash CLI
  ant beta:sessions:events send \
    --session-id "$SESSION_ID" \
    --event "{type: user.interrupt, session_thread_id: $THREAD_ID}"
  ```

  ```python Python
  client.beta.sessions.events.send(
      session.id,
      events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
  )
  ```

  ```typescript TypeScript
  await client.beta.sessions.events.send(session.id, {
    events: [{ type: "user.interrupt", session_thread_id: thread.id }]
  });
  ```

  ```csharp C#
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserInterruptEventParams
          {
              Type = BetaManagedAgentsUserInterruptEventParamsType.UserInterrupt,
              SessionThreadID = thread.ID,
          },
      ],
  });
  ```

  ```go Go
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  		OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{
  			Type:            anthropic.BetaManagedAgentsUserInterruptEventParamsTypeUserInterrupt,
  			SessionThreadID: anthropic.String(thread.ID),
  		},
  	}},
  }); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsUserInterruptEventParams.builder()
              .type(BetaManagedAgentsUserInterruptEventParams.Type.USER_INTERRUPT)
              .sessionThreadId(thread.id())
              .build())
          .build());
  ```

  ```php PHP
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          ['type' => 'user.interrupt', 'session_thread_id' => $thread->id],
      ],
  );
  ```

  ```ruby Ruby
  client.beta.sessions.events.send_(
    session.id,
    events: [{type: "user.interrupt", session_thread_id: thread.id}]
  )
  ```
</CodeGroup>

Sul thread di un subagente bloccato in `requires_action`, l'interruzione chiude ogni chiamata allo strumento in sospeso con un risultato di errore dello strumento ("Tool execution was interrupted before completion. Please retry.") e riemette direttamente `session.thread_status_idle` con `stop_reason: end_turn`; il modello non viene campionato. Su un thread figlio inattivo con `end_turn` o `budget_reached`, l'interruzione non ha alcun effetto. Un'interruzione che indica un thread terminato restituisce un errore 400. Un thread figlio interrotto non invia all'agente del thread principale il report che invia quando un turno termina. Mentre quell'agente attende il thread figlio, non avvia un altro turno finché non gli arriva qualcos'altro, come un `user.message` o il report di un altro thread.

## Archiviare un thread di sessione

Facoltativamente, archivia un thread di sessione quando ha completato il suo lavoro. Archiviare un thread libera il suo posto nel limite di 25 thread figli. Il server archivia autonomamente i thread di un'[esecuzione di workflow](https://platform.claude.com/docs/it/managed-agents/workflow-runs). Non è necessario archiviarli, e non puoi farlo mentre l'esecuzione è aperta.

<CodeGroup>
  ```bash cURL
  curl -fsS -X POST "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/archive" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01"
  ```

  ```bash CLI
  ant beta:sessions:threads archive \
    --session-id "$SESSION_ID" \
    --thread-id "$THREAD_ID"
  ```

  ```python Python
  archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
  print(archived.status, archived.archived_at)
  ```

  ```typescript TypeScript
  const archived = await client.beta.sessions.threads.archive(thread.id, {
    session_id: session.id
  });
  console.log(archived.status, archived.archived_at);
  ```

  ```csharp C#
  var archived = await client.Beta.Sessions.Threads.Archive(thread.ID, new() { SessionID = session.ID });
  Console.WriteLine($"{archived.Status} {archived.ArchivedAt}");
  ```

  ```go Go
  archived, err := client.Beta.Sessions.Threads.Archive(ctx, thread.ID, anthropic.BetaSessionThreadArchiveParams{
  	SessionID: session.ID,
  })
  if err != nil {
  	panic(err)
  }
  fmt.Println(archived.Status, archived.ArchivedAt)
  ```

  ```java Java
  var archived = client.beta().sessions().threads().archive(
      thread.id(),
      ThreadArchiveParams.builder()
          .sessionId(session.id())
          .build());
  IO.println(archived.status() + " " + archived.archivedAt().orElseThrow());
  ```

  ```php PHP
  $archived = $client->beta->sessions->threads->archive($thread->id, sessionID: $session->id);
  echo "{$archived->status} {$archived->archivedAt->format(DATE_ATOM)}\n";
  ```

  ```ruby Ruby
  archived = client.beta.sessions.threads.archive(thread.id, session_id: session.id)
  puts "#{archived.status} #{archived.archived_at}"
  ```
</CodeGroup>

L'archiviazione riesce solo se il thread è `idle`. Un thread fermo in `requires_action` conta come inattivo e può essere archiviato direttamente; solo un thread in esecuzione deve essere prima interrotto:

<CodeGroup>
  ```bash cURL
  # Interrompi il thread, poi archivialo
  curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{"events": [{"type": "user.interrupt", "session_thread_id": "'"$THREAD_ID"'"}]}'

  curl -fsS -X POST "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/archive" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01"
  ```

  ```bash CLI
  ant beta:sessions:events send \
    --session-id "$SESSION_ID" \
    --event "{type: user.interrupt, session_thread_id: $THREAD_ID}"

  ant beta:sessions:threads archive \
    --session-id "$SESSION_ID" \
    --thread-id "$THREAD_ID"
  ```

  ```python Python
  client.beta.sessions.events.send(
      session.id,
      events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
  )
  archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
  print(archived.status, archived.archived_at)
  ```

  ```typescript TypeScript
  await client.beta.sessions.events.send(session.id, {
    events: [{ type: "user.interrupt", session_thread_id: thread.id }]
  });
  const archived = await client.beta.sessions.threads.archive(thread.id, {
    session_id: session.id
  });
  console.log(archived.status, archived.archived_at);
  ```

  ```csharp C#
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserInterruptEventParams
          {
              Type = BetaManagedAgentsUserInterruptEventParamsType.UserInterrupt,
              SessionThreadID = thread.ID,
          },
      ],
  });
  archived = await client.Beta.Sessions.Threads.Archive(thread.ID, new() { SessionID = session.ID });
  Console.WriteLine($"{archived.Status} {archived.ArchivedAt}");
  ```

  ```go Go
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  		OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{
  			Type:            anthropic.BetaManagedAgentsUserInterruptEventParamsTypeUserInterrupt,
  			SessionThreadID: anthropic.String(thread.ID),
  		},
  	}},
  }); err != nil {
  	panic(err)
  }

  archived, err := client.Beta.Sessions.Threads.Archive(ctx, thread.ID, anthropic.BetaSessionThreadArchiveParams{
  	SessionID: session.ID,
  })
  if err != nil {
  	panic(err)
  }
  fmt.Println(archived.Status, archived.ArchivedAt)
  ```

  ```java Java
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsUserInterruptEventParams.builder()
              .type(BetaManagedAgentsUserInterruptEventParams.Type.USER_INTERRUPT)
              .sessionThreadId(thread.id())
              .build())
          .build());

  archived = client.beta().sessions().threads().archive(
      thread.id(),
      ThreadArchiveParams.builder()
          .sessionId(session.id())
          .build());
  IO.println(archived.status() + " " + archived.archivedAt().orElseThrow());
  ```

  ```php PHP
  $client->beta->sessions->events->send(
      $session->id,
      events: [['type' => 'user.interrupt', 'session_thread_id' => $thread->id]],
  );
  $archived = $client->beta->sessions->threads->archive($thread->id, sessionID: $session->id);
  echo "{$archived->status} {$archived->archivedAt->format(DATE_ATOM)}\n";
  ```

  ```ruby Ruby
  client.beta.sessions.events.send_(
    session.id,
    events: [{type: "user.interrupt", session_thread_id: thread.id}]
  )
  archived = client.beta.sessions.threads.archive(thread.id, session_id: session.id)
  puts "#{archived.status} #{archived.archived_at}"
  ```
</CodeGroup>

## Eventi del thread principale

Questi eventi mostrano l'attività multiagente sul thread principale in `/v1/sessions/{session_id}/events/stream`. Gli eventi relativi alla direzione dei messaggi sono denominati rispetto al thread sul cui stream compaiono: `agent.thread_message_received` significa che un messaggio è arrivato su questo thread da un altro thread, e `agent.thread_message_sent` significa che questo thread ne ha inviato uno. L'attività che l'agente del thread principale delega, ad esempio, arriva sullo stream del thread figlio come evento `agent.thread_message_received`.

| Tipo                               | Descrizione                                                                                                                                                                                                                                                                                                                                                |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `session.thread_created`           | È stato creato un thread. Include `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) e `agent_name` (java, php: `agentName`; csharp, go: `AgentName`).                                                                                                                                                   |
| `session.thread_status_running`    | Un thread ha avviato un'attività.                                                                                                                                                                                                                                                                                                                          |
| `session.thread_status_idle`       | L'agente associato al thread è in attesa di input. Include uno `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) che indica perché l'agente si è fermato.                                                                                                                                                                                  |
| `session.thread_status_terminated` | Un thread è terminato e non accetta ulteriori input, ad esempio perché è stato archiviato o ha riscontrato un errore irrecuperabile. Anche un thread advisor termina quando la sua consultazione finisce.                                                                                                                                                  |
| `agent.thread_message_received`    | Sul thread principale, un subagente ha inviato all'agente del thread principale un report o una domanda. Include `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`), `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`) e `content` (csharp, go: `Content`).   |
| `agent.thread_message_sent`        | Sul thread principale, l'agente del thread principale ha inviato a un subagente un'attività o un messaggio di follow-up. Include `to_session_thread_id` (java: `toSessionThreadId`; php: `toSessionThreadID`; csharp, go: `ToSessionThreadID`), `to_agent_name` (java, php: `toAgentName`; csharp, go: `ToAgentName`) e `content` (csharp, go: `Content`). |

Le consultazioni dell'advisor emettono questi stessi eventi di thread con il nome riservato `anthropic.advisor` (come `agent_name` (java, php: `agentName`; csharp, go: `AgentName`) negli eventi del ciclo di vita del thread e come `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`) nella consegna del consiglio); consulta [Fornisci un advisor alla sessione](https://platform.claude.com/docs/it/managed-agents/multiagent-orchestration#give-the-session-an-advisor) per la sequenza.

I thread di un'[esecuzione di workflow](https://platform.claude.com/docs/it/managed-agents/workflow-runs) compaiono sullo stream principale come segue:

* **Eventi del ciclo di vita:** Ogni thread di un'esecuzione invia `session.thread_created`, con il `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) dell'esecuzione, e i suoi eventi `session.thread_status_running`, `session.thread_status_idle` e `session.thread_status_terminated`.
* **Eventi dei messaggi:** Il prompt di un thread di un'esecuzione, un evento `agent.thread_message_received`, rimane sul proprio stream.
* **Eventi dell'esecuzione:** Anche gli eventi `workflow_run.*` arrivano su questo stream; consulta [Eventi dell'esecuzione](https://platform.claude.com/docs/it/managed-agents/workflow-runs#run-events).
* **Chiamate agli strumenti che attendono te:** Le chiamate agli strumenti di un thread di un'esecuzione che richiedono il tuo client vengono ripubblicate su questo stream, come per qualsiasi thread figlio. Consulta [Autorizzazioni degli strumenti e strumenti personalizzati](https://platform.claude.com/docs/it/managed-agents/session-threads#tool-permissions-and-custom-tools).

## Eventi dei thread di sessione

Gli eventi critici vengono inoltrati al thread principale. Tuttavia, potresti comunque voler esaminare il ragionamento e le chiamate agli strumenti di un agente specifico. Per farlo, esegui lo streaming o elenca gli eventi dal thread di sessione associato.

Ogni thread di sessione ha il proprio stream di eventi in `/v1/sessions/{session_id}/threads/{thread_id}/stream`, che accetta lo stesso parametro `event_deltas[]` dello stream a livello di sessione, così puoi visualizzare in anteprima il testo di un subagente mentre il modello lo genera. Una connessione mostra in anteprima solo il thread che sta leggendo: le anteprime di un thread figlio non compaiono mai sullo stream a livello di sessione, quindi per osservare un subagente in tempo reale, apri lo stream del suo thread. Consulta [Visualizzare in anteprima gli eventi dei thread di sessione](https://platform.claude.com/docs/it/managed-agents/event-deltas#preview-session-thread-events) per l'attivazione, l'accumulo e la riconciliazione delle anteprime.

In un'esecuzione di workflow, il server esegue un workflow: un programma scritto dall'agente del thread principale. Su ciascuno dei thread dell'esecuzione, il primo `agent.thread_message_received` è il prompt scritto dal workflow. Il suo `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`) è l'ID del thread principale, e l'API non imposta il suo `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`). L'API non garantisce il testo del prompt, quindi non analizzarlo. L'evento `session.thread_status_terminated` del thread, sullo stream del thread principale, ti indica che il thread ha terminato. Nessun evento registra il risultato che ha restituito al workflow.

Lo stream di un thread non riproduce gli eventi precedenti. Subito dopo `session.thread_created`, l'elenco degli eventi di un thread di un'esecuzione può essere vuoto, perché il server scrive il primo evento del thread dopo di esso. Quindi apri prima lo stream del thread, poi elenca gli eventi del thread e salta ogni evento in streaming il cui `id` (csharp, go: `ID`) è stato restituito dall'elenco.

<Tabs>
  <Tab title="Streaming degli eventi del thread di sessione">
    <CodeGroup>
      ```bash cURL
      curl -fsSN "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/stream?beta=true" \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "anthropic-beta: managed-agents-2026-04-01"
      ```

      ```bash CLI
      ant beta:sessions:threads:events stream \
        --session-id "$SESSION_ID" \
        --thread-id "$THREAD_ID"
      ```

      ```python Python
      with client.beta.sessions.threads.events.stream(
          thread.id,
          session_id=session.id,
      ) as stream:
          for event in stream:
              match event.type:
                  case "agent.message":
                      for block in event.content:
                          if block.type == "text":
                              print(block.text, end="")
                  case "session.thread_status_idle":
                      break
      ```

      ```typescript TypeScript
      const stream = await client.beta.sessions.threads.events.stream(thread.id, {
        session_id: session.id
      });

      loop: for await (const event of stream) {
        switch (event.type) {
          case "agent.message":
            for (const block of event.content) {
              if (block.type === "text") {
                process.stdout.write(block.text);
              }
            }
            break;
          case "session.thread_status_idle":
            break loop;
        }
      }
      ```

      ```csharp C#
      await foreach (var evt in client.Beta.Sessions.Threads.Events.StreamStreaming(thread.ID, new() { SessionID = session.ID }))
      {
          if (evt.Value is BetaManagedAgentsAgentMessageEvent message)
          {
              foreach (var block in message.Content)
              {
                  if (block.Value is BetaManagedAgentsTextBlock textBlock)
                  {
                      Console.Write(textBlock.Text);
                  }
              }
          }
          else if (evt.Value is BetaManagedAgentsSessionThreadStatusIdleEvent)
          {
              break;
          }
      }
      ```

      ```go Go
      	stream := client.Beta.Sessions.Threads.Events.StreamEvents(ctx, thread.ID, anthropic.BetaSessionThreadEventStreamParams{
      		SessionID: session.ID,
      	})
      	defer stream.Close()

      loop:
      	for stream.Next() {
      		event := stream.Current()
      		switch event.Type {
      		case "agent.message":
      			for _, block := range event.AsAgentMessage().Content {
      				if block.Type == "text" {
      					fmt.Print(block.Text)
      				}
      			}
      		case "session.thread_status_idle":
      			break loop
      		}
      	}
      	if err := stream.Err(); err != nil {
      		panic(err)
      	}
      ```

      ```java Java
      try (var streamResponse = client.beta().sessions().threads().events().streamStreaming(
          thread.id(),
          EventStreamParams.builder().sessionId(session.id()).build()
      )) {
          loop:
          for (var event : (Iterable<BetaManagedAgentsStreamSessionThreadEvents>) streamResponse.stream()::iterator) {
              switch (event.type().value()) {
                  case AGENT_MESSAGE -> {
                      for (var block : event.asAgentMessage().content()) {
                          block.text().ifPresent(textBlock -> IO.print(textBlock.text()));
                      }
                  }
                  case SESSION_THREAD_STATUS_IDLE -> {
                      break loop;
                  }
              }
          }
      }
      ```

      ```php PHP
      $stream = $client->beta->sessions->threads->events->streamStream(
          $thread->id,
          sessionID: $session->id,
      );

      foreach ($stream as $event) {
          switch (true) {
              case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent:
                  foreach ($event->content as $block) {
                      if ($block instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock) {
                          echo $block->text;
                      }
                  }
                  break;
              case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionThreadStatusIdleEvent:
                  break 2;
          }
      }
      ```

      ```ruby Ruby
      client.beta.sessions.threads.events.stream_events(thread.id, session_id: session.id).each do |event|
        case event
        when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
          event.content.each do |block|
            print block.text if block.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsTextBlock)
          end
        when Anthropic::Beta::Sessions::BetaManagedAgentsSessionThreadStatusIdleEvent
          break
        end
      end
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Elencare gli eventi del thread di sessione">
    Elenca tutti gli eventi passati del thread di sessione per ottenere una cronologia completa.

    <CodeGroup>
      ```bash cURL
      curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/events" \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "anthropic-beta: managed-agents-2026-04-01"
      ```

      ```bash CLI
      ant beta:sessions:threads:events list \
        --session-id "$SESSION_ID" \
        --thread-id "$THREAD_ID"
      ```

      ```python Python
      for event in client.beta.sessions.threads.events.list(
          thread.id,
          session_id=session.id,
      ):
          print(f"[{event.type}] {event.processed_at}")
      ```

      ```typescript TypeScript
      for await (const event of client.beta.sessions.threads.events.list(thread.id, {
        session_id: session.id
      })) {
        console.log(`[${event.type}] ${event.processed_at}`);
      }
      ```

      ```csharp C#
      var page = await client.Beta.Sessions.Threads.Events.List(thread.ID, new() { SessionID = session.ID });
      await foreach (var evt in page.Paginate())
      {
          Console.WriteLine($"[{evt.Json.GetProperty("type").GetString()}] {evt.ProcessedAt}");
      }
      ```

      ```go Go
      pager := client.Beta.Sessions.Threads.Events.ListAutoPaging(ctx, thread.ID, anthropic.BetaSessionThreadEventListParams{
      	SessionID: session.ID,
      })
      for pager.Next() {
      	event := pager.Current()
      	fmt.Printf("[%s] %s\n", event.Type, event.ProcessedAt)
      }
      if err := pager.Err(); err != nil {
      	panic(err)
      }
      ```

      ```java Java
      for (var event : client.beta().sessions().threads().events().list(
              thread.id(),
              EventListParams.builder().sessionId(session.id()).build()
          ).autoPager()) {
          var type = event._json().orElseThrow() instanceof JsonObject json
              ? json.values().get("type").asStringOrThrow()
              : "unknown";
          var processedAt = event.processedAt().map(OffsetDateTime::toString).orElse("pending");
          IO.println("[" + type + "] " + processedAt);
      }
      ```

      ```php PHP
      foreach (
          $client->beta->sessions->threads->events->list(
              $thread->id,
              sessionID: $session->id,
          )->pagingEachItem() as $event
      ) {
          echo "[{$event->type}] {$event->processedAt->format(DATE_RFC3339)}\n";
      }
      ```

      ```ruby Ruby
      client.beta.sessions.threads.events.list(
        thread.id,
        session_id: session.id
      ).auto_paging_each do |event|
        puts "[#{event.type}] #{event.processed_at}"
      end
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Autorizzazioni degli strumenti e strumenti personalizzati

Se un subagente ha bisogno di qualcosa dal tuo client, come l'[autorizzazione](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#tool-confirmation) per eseguire una chiamata a uno strumento o il [risultato di uno strumento personalizzato](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#handling-custom-tool-calls), l'evento viene ripubblicato sul **thread principale** con `session_thread_id` che identifica il thread di sessione di origine. Una chiamata a uno strumento richiede la tua autorizzazione con `always_ask`, oppure con [`auto`](https://platform.claude.com/docs/it/managed-agents/permission-policies#let-the-server-evaluate-each-call-with-auto) quando il server non giunge a una determinazione.

```json
{
  "type": "session.thread_status_idle",
  "id": "sevt_01ABC...",
  "session_thread_id": "sthr_01DEF...",
  "agent_name": "code-reviewer",
  "stop_reason": {
    "type": "requires_action",
    "event_ids": ["sevt_01XYZ..."]
  }
}
```

Pubblica `user.tool_confirmation` (con `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`)) o `user.custom_tool_result` (con `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)); il server instrada automaticamente la risposta al thread corretto. La risposta può comparire sul thread principale e sul thread del subagente con valori di `id` (csharp, go: `ID`) diversi. Per far corrispondere le due copie, confronta `type` (csharp, go: `Type`) e `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) (o `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)), non `id` (csharp, go: `ID`).

La sessione passa a `idle` solo quando nessun thread è `running`, quindi `session.status_idle` può arrivare molto tempo dopo la chiamata di un subagente. Non devi attenderlo: invia `user.custom_tool_result` non appena arriva l'evento `agent.custom_tool_use` ripubblicato.

Con `auto`, i tuoi eventi `user.message` possono portare il server a consentire una chiamata che altrimenti negherebbe. Nulla nel thread di un subagente conta come tua intenzione. Il tuo client non pubblica messaggi lì, e i messaggi che l'agente del thread principale invia al subagente non contano. Quando il server nega una chiamata con `auto`, nulla viene ripubblicato: l'evento e il risultato di errore dello strumento compaiono solo sullo [stream del thread](https://platform.claude.com/docs/it/managed-agents/session-threads#session-thread-events) del subagente, e il subagente continua a essere eseguito.

L'esempio seguente va inserito all'interno del ciclo di eventi del [gestore della conferma degli strumenti](https://platform.claude.com/docs/it/managed-agents/events-and-streaming#tool-confirmation). Per ogni ID in `stop_reason.event_ids`, invia un `user.tool_confirmation` che consente la chiamata. Lo stesso schema si applica a `user.custom_tool_result`, che puoi anche inviare non appena arriva il relativo evento `agent.custom_tool_use`.

<CodeGroup exclude="shell:cURL, shell:CLI">
  <CodeGroupItem language="cURL">
    Questo workflow 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 workflow 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
  for event_id in stop.event_ids:
      client.beta.sessions.events.send(
          session.id,
          events=[
              {
                  "type": "user.tool_confirmation",
                  "tool_use_id": event_id,
                  "result": "allow",
              }
          ],
      )
  ```

  ```typescript TypeScript
  for (const eventId of stop.event_ids) {
    await client.beta.sessions.events.send(session.id, {
      events: [
        {
          type: "user.tool_confirmation",
          tool_use_id: eventId,
          result: "allow"
        }
      ]
    });
  }
  ```

  ```csharp C#
  foreach (var eventId in requiresAction.EventIds)
  {
      await client.Beta.Sessions.Events.Send(session.ID, new()
      {
          Events =
          [
              new BetaManagedAgentsUserToolConfirmationEventParams
              {
                  Type = BetaManagedAgentsUserToolConfirmationEventParamsType.UserToolConfirmation,
                  ToolUseID = eventId,
                  Result = BetaManagedAgentsUserToolConfirmationEventParamsResult.Allow,
              },
          ],
      });
  }
  ```

  ```go Go
  for _, eventID := range stopReason.EventIDs {
  	params := anthropic.BetaManagedAgentsUserToolConfirmationEventParams{
  		Type:      anthropic.BetaManagedAgentsUserToolConfirmationEventParamsTypeUserToolConfirmation,
  		ToolUseID: eventID,
  		Result:    anthropic.BetaManagedAgentsUserToolConfirmationEventParamsResultAllow,
  	}
  	if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{OfUserToolConfirmation: &params}},
  	}); err != nil {
  		panic(err)
  	}
  }
  ```

  ```java Java
  for (var eventId : pendingToolUseIds) {
      client.beta().sessions().events().send(
          session.id(),
          EventSendParams.builder()
              .addEvent(BetaManagedAgentsUserToolConfirmationEventParams.builder()
                  .type(BetaManagedAgentsUserToolConfirmationEventParams.Type.USER_TOOL_CONFIRMATION)
                  .toolUseId(eventId)
                  .result(BetaManagedAgentsUserToolConfirmationEventParams.Result.ALLOW)
                  .build())
              .build()
      );
  }
  ```

  ```php PHP
  foreach ($event->stopReason->eventIDs as $eventId) {
      $client->beta->sessions->events->send($session->id, events: [[
          'type' => 'user.tool_confirmation',
          'tool_use_id' => $eventId,
          'result' => 'allow',
      ]]);
  }
  ```

  ```ruby Ruby
  event_ids.each do |event_id|
    client.beta.sessions.events.send_(session.id, events: [{
      type: "user.tool_confirmation",
      tool_use_id: event_id,
      result: "allow"
    }])
  end
  ```
</CodeGroup>

Lo schema precedente risponde alle chiamate elencate da un evento di inattività. Sullo stream principale, l'evento `session.thread_status_idle` di un subagente può arrivare prima degli eventi `agent.tool_use` o `agent.mcp_tool_use` elencati nel suo `stop_reason.event_ids`. Un `user.tool_confirmation` per una chiamata il cui evento non è ancora arrivato può restituire 400. Per evitarlo, rispondi a ogni chiamata il cui [`evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`)](https://platform.claude.com/docs/it/managed-agents/permission-policies#see-how-each-call-was-evaluated) è `ask` quando il relativo evento arriva sullo stream principale.
