---
title: Session-Event-Stream
url: https://platform.claude.com/docs/de/managed-agents/events-and-streaming
description: Sende Events, streame Antworten und unterbrich oder lenke deine Session während der Ausführung um.
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

Die Kommunikation mit Claude Managed Agents ist eventbasiert. Du öffnest einen Stream, um eine Session zu verfolgen, sendest Events, um sie zu steuern, und antwortest ihr, wenn sie für eine Eingabe pausiert.

## Event-Typen

Events fließen in zwei Richtungen: Du sendest Events an den Agenten, und die Session sendet Events an dich zurück.

* **Events, die du sendest:** `user.*`-Events starten eine Session und steuern sie im weiteren Verlauf. [`system.message`](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#send-system-messages)-Events fügen Kontext auf Systemebene hinzu.
* **Events, die du empfängst:** Session-Events, Span-Events und Agent-Events melden den Zustand der Session und den Fortschritt des Agenten.

Diese Event-Typ-Strings folgen der Namenskonvention `{domain}.{action}`. Den vollständigen Katalog findest du unter [Event-Typen](https://platform.claude.com/docs/de/managed-agents/reference#event-types) in der Referenz.

[Webhook-Event-Typen](https://platform.claude.com/docs/de/managed-agents/webhooks#supported-event-types) sind davon getrennt, und einige ihrer Namen unterscheiden sich von denen des Streams. Webhooks verwenden zum Beispiel `session.status_idled` statt `session.status_idle`.

## Events streamen

Streame Events aus der Session, um Echtzeit-Updates zu erhalten, während der Agent arbeitet. Ein Stream liefert nur die Events, die nach seinem Öffnen ausgegeben werden. Öffne den Stream daher, bevor du Events sendest, um eine „race condition" (Wettlaufsituation) zu vermeiden.

<CodeGroup>
  ```bash cURL
  # Öffne den Stream, bevor du das erste Event sendest: Nur spätere Events werden zugestellt.
  curl --fail-with-body -sS -N \
    "https://api.anthropic.com/v1/sessions/$SESSION_ID/events/stream?beta=true" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "accept: text/event-stream"
  ```

  ```bash CLI
  # Öffne den Stream, bevor du das erste Event sendest: Nur spätere Events werden zugestellt.
  ant beta:sessions:events stream --session-id "$SESSION_ID"
  ```

  ```python Python
  # Öffne zuerst den Stream, sende dann die Benutzernachricht
  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": "Summarize the repo README"}],
              },
          ],
      )

      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.status_idle":
                  break
              case "session.error":
                  error_message = event.error.message if event.error else "unknown"
                  print(f"\n[Error: {error_message}]")
                  break
  ```

  ```typescript TypeScript
  // Öffne zuerst den Stream, sende dann die Benutzernachricht
  const stream = await client.beta.sessions.events.stream(session.id);
  await client.beta.sessions.events.send(session.id, {
    events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "Summarize the repo README" }]
      }
    ]
  });

  events: 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.status_idle":
        break events;
      case "session.error":
        console.log(`\n[Error: ${event.error?.message ?? "unknown"}]`);
        break events;
    }
  }
  ```

  ```csharp C#
  // Öffne zuerst den Stream und sende dann die Benutzernachricht
  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(session.ID);
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Summarize the repo README",
                  },
              ],
          },
      ],
  });

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.Value is BetaManagedAgentsAgentMessageEvent message)
      {
          foreach (var block in message.Content)
          {
              if (block.Value is BetaManagedAgentsTextBlock textBlock)
              {
                  Console.Write(textBlock.Text);
              }
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent)
      {
          break;
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionErrorEvent error)
      {
          Console.WriteLine($"\n[Error: {error.Error?.Message ?? "unknown"}]");
          break;
      }
  }
  ```

  ```go Go
  	// Öffne zuerst den Stream, dann sende die Benutzernachricht
  	stream := client.Beta.Sessions.Events.StreamEvents(ctx, session.ID, anthropic.BetaSessionEventStreamParams{})
  	defer stream.Close()

  	if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  						Text: "Summarize the repo README",
  					},
  				}},
  			},
  		}},
  	}); err != nil {
  		panic(err)
  	}

  events:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsAgentMessageEvent:
  			// konkret typisierte Liste: BetaManagedAgentsTextBlock
  			for _, block := range event.Content {
  				fmt.Print(block.Text)
  			}
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			break events
  		case anthropic.BetaManagedAgentsSessionErrorEvent:
  			fmt.Printf("\n[Error: %s]\n", cmp.Or(event.Error.Message, "unknown"))
  			break events
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  // Öffne zuerst den Stream, dann sende die Benutzernachricht
  try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
      client.beta().sessions().events().send(
          session.id(),
          EventSendParams.builder()
              .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                  .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
                  .addTextContent("Summarize the repo README")
                  .build())
              .build()
      );

      Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
      events:
      for (var event : events) {
          switch (event.type().value()) {
              case AGENT_MESSAGE -> event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
              case SESSION_STATUS_IDLE -> {
                  break events;
              }
              case SESSION_ERROR -> {
                  // Das Feld `message` gibt es in allen Fehlervarianten; lies es aus dem rohen JSON.
                  var errorMessage =
                      event.asSessionError().error()._json().orElse(null) instanceof JsonObject json
                          ? json.values().get("message").asStringOrThrow()
                          : "unknown";
                  IO.println("\n[Error: " + errorMessage + "]");
                  break events;
              }
          }
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionErrorEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;

  // Öffne zuerst den Stream und sende dann die Benutzernachricht
  $stream = $client->beta->sessions->events->streamStream($session->id);
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          [
              'type' => 'user.message',
              'content' => [['type' => 'text', 'text' => 'Summarize the repo README']],
          ],
      ],
  );

  foreach ($stream as $event) {
      match (true) {
          $event instanceof ManagedAgentsAgentMessageEvent => array_walk(
              $event->content,
              static fn ($block) => $block instanceof ManagedAgentsTextBlock ? print($block->text) : null,
          ),
          $event instanceof ManagedAgentsSessionErrorEvent => printf("\n[Error: %s]", $event->error?->message ?? 'unknown'),
          default => null,
      };
      if ($event->type === 'session.status_idle' || $event->type === 'session.error') {
          break;
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  # Öffne zuerst den Stream, sende dann die Benutzernachricht
  stream = client.beta.sessions.events.stream_events(session.id)

  client.beta.sessions.events.send_(
    session.id,
    events: [{
      type: "user.message",
      content: [{type: "text", text: "Summarize the repo README"}]
    }]
  )

  stream.each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
      event.content.each { print it.text }
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      break
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionErrorEvent
      puts "\n[Error: #{event.error&.message || "unknown"}]"
      break
    else
      # andere Event-Typen ignorieren
    end
  end
  ```
</CodeGroup>

Die Session meldet Fehler über das Event `session.error`. Seine Felder findest du unter [Event-Typen](https://platform.claude.com/docs/de/managed-agents/reference#event-types).

Der Antworttext des Agenten kommt als gepufferte `agent.message`-Events an, die jeweils erst ausgegeben werden, nachdem die Modellanfrage, die sie erzeugt hat, abgeschlossen ist. Um den Text darzustellen, während das Modell ihn noch generiert, siehe [Antworten mit Event-Deltas vorab anzeigen](https://platform.claude.com/docs/de/managed-agents/event-deltas).

### Ohne verpasste Events neu verbinden

Um dich ohne verpasste Events erneut mit einer bestehenden Session zu verbinden, kombiniere einen neuen Stream mit dem Event-Verlauf:

1. Öffne einen neuen Stream.
2. [Liste den vollständigen Event-Verlauf auf](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#list-past-events), um eine Menge bereits gesehener Event-IDs anzulegen.
3. Verfolge den Live-Stream und überspringe dabei alle Events, die bereits von der Verlaufsliste zurückgegeben wurden.

<CodeGroup exclude="shell:cURL, shell:CLI">
  <CodeGroupItem language="cURL">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  ```python Python
  with client.beta.sessions.events.stream(session.id) as stream:
      # Der Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
      history = client.beta.sessions.events.list(session.id)
      seen_event_ids = {past_event.id for past_event in history}

      # Verfolge Live-Events und überspringe bereits gesehene
      for event in stream:
          if event.type == "event_start" or event.type == "event_delta":
              # Delta-Vorschauen sind für diese Verbindung nicht aktiviert.
              continue
          if event.id in seen_event_ids:
              continue
          seen_event_ids.add(event.id)
          match event.type:
              case "agent.message":
                  for block in event.content:
                      if block.type == "text":
                          print(block.text, end="")
              case "session.status_idle":
                  break
  ```

  ```typescript TypeScript
  const seenEventIds = new Set<string>();
  const stream = await client.beta.sessions.events.stream(session.id);

  // Der Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
  for await (const event of client.beta.sessions.events.list(session.id)) {
    seenEventIds.add(event.id);
  }

  // Verfolge Live-Events und überspringe bereits gesehene
  tail: for await (const event of stream) {
    // Vorschau-Events (event_start/event_delta) haben keine id auf oberster Ebene
    if (event.type === "event_start" || event.type === "event_delta") {
      continue;
    }
    if (seenEventIds.has(event.id)) {
      continue;
    }
    seenEventIds.add(event.id);
    switch (event.type) {
      case "agent.message":
        for (const block of event.content) {
          if (block.type === "text") {
            process.stdout.write(block.text);
          }
        }
        break;
      case "session.status_idle":
        break tail;
    }
  }
  ```

  ```csharp C#
  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(session.ID);

  // Der Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
  HashSet<string> seenEventIds = [];
  var history = await client.Beta.Sessions.Events.List(session.ID);
  await foreach (var pastEvent in history.Paginate())
  {
      seenEventIds.Add(pastEvent.ID);
  }

  // Verfolge Live-Events und überspringe bereits gesehene
  await foreach (var streamEvent in stream.Enumerate())
  {
      if (!seenEventIds.Add(streamEvent.ID))
      {
          continue;
      }
      if (streamEvent.Value is BetaManagedAgentsAgentMessageEvent message)
      {
          foreach (var block in message.Content)
          {
              if (block.Value is BetaManagedAgentsTextBlock textBlock)
              {
                  Console.Write(textBlock.Text);
              }
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent)
      {
          break;
      }
  }
  ```

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

  	// Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
  	seenEventIDs := map[string]struct{}{}
  	history := client.Beta.Sessions.Events.ListAutoPaging(ctx, session.ID, anthropic.BetaSessionEventListParams{})
  	for history.Next() {
  		seenEventIDs[history.Current().ID] = struct{}{}
  	}
  	if err := history.Err(); err != nil {
  		panic(err)
  	}

  	// Verfolge Live-Events und überspringe bereits gesehene
  tail:
  	for stream.Next() {
  		event := stream.Current()
  		if _, seen := seenEventIDs[event.ID]; seen {
  			continue
  		}
  		seenEventIDs[event.ID] = struct{}{}
  		switch event := event.AsAny().(type) {
  		case anthropic.BetaManagedAgentsAgentMessageEvent:
  			// konkret typisierte Liste: BetaManagedAgentsTextBlock
  			for _, block := range event.Content {
  				fmt.Print(block.Text)
  			}
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			break tail
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
      // Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
      // Jede Event-Variante hat `id`; lies sie aus dem rohen JSON, um variantenübergreifend zu deduplizieren.
      var seenEventIds = new HashSet<String>();
      for (var pastEvent : client.beta().sessions().events().list(session.id()).autoPager()) {
          if (pastEvent._json().orElseThrow() instanceof JsonObject json) {
              seenEventIds.add(json.values().get("id").asStringOrThrow());
          }
      }

      // Live-Events mitlesen; Set.add gibt false für bereits gesehene IDs zurück und überspringt so den Replay.
      stream.stream()
          .filter(event -> event._json().orElseThrow() instanceof JsonObject json
              && seenEventIds.add(json.values().get("id").asStringOrThrow()))
          .takeWhile(event -> !event.isSessionStatusIdle())
          .filter(BetaManagedAgentsStreamSessionEvents::isAgentMessage)
          .forEach(event -> event.asAgentMessage().content()
              .forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text()))));
  }
  ```

  ```php PHP
  use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;

  $stream = $client->beta->sessions->events->streamStream($session->id);

  // Der Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
  $seenEventIds = [];
  foreach ($client->beta->sessions->events->list($session->id)->pagingEachItem() as $event) {
      $seenEventIds[$event->id] = true;
  }

  // Live-Events mitlesen und bereits Gesehenes überspringen
  foreach ($stream as $event) {
      if (isset($seenEventIds[$event->id])) {
          continue;
      }
      $seenEventIds[$event->id] = true;
      match (true) {
          $event instanceof ManagedAgentsAgentMessageEvent => array_walk(
              $event->content,
              static fn ($block) => $block instanceof ManagedAgentsTextBlock ? print($block->text) : null,
          ),
          default => null,
      };
      if ($event->type === 'session.status_idle') {
          break;
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  stream = client.beta.sessions.events.stream_events(session.id)

  # Stream ist offen und puffert. Liste den Verlauf auf, bevor du live mitliest.
  seen_event_ids = Set.new
  client.beta.sessions.events.list(session.id).auto_paging_each { seen_event_ids << it.id }

  # Live-Events verfolgen, bereits Gesehenes überspringen — Set#add? gibt nil für Duplikate zurück
  stream.each do |event|
    next unless seen_event_ids.add?(event.id)
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
      event.content.each { print it.text }
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      break
    else
      # andere Event-Typen ignorieren
    end
  end
  ```
</CodeGroup>

## Events senden

Sende ein `user.message`-Event, um die Arbeit des Agenten zu starten oder fortzusetzen:

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS "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.message",
          "content": [
            {"type": "text", "text": "Analyze the performance of the sort function in utils.py"}
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
  events:
    - type: user.message
      content:
        - type: text
          text: Analyze the performance of the sort function in utils.py
  YAML
  ```

  ```python Python
  client.beta.sessions.events.send(
      session.id,
      events=[
          {
              "type": "user.message",
              "content": [
                  {
                      "type": "text",
                      "text": "Analyze the performance of the sort function in utils.py",
                  },
              ],
          },
      ],
  )
  ```

  ```typescript TypeScript
  await client.beta.sessions.events.send(session.id, {
    events: [
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Analyze the performance of the sort function in utils.py"
          }
        ]
      }
    ]
  });
  ```

  ```csharp C#
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Analyze the performance of the sort function in utils.py",
                  },
              ],
          },
      ],
  });
  ```

  ```go Go
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  		OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  			Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  			Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  				OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  					Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  					Text: "Analyze the performance of the sort function in utils.py",
  				},
  			}},
  		},
  	}},
  }); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
              .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
              .addTextContent("Analyze the performance of the sort function in utils.py")
              .build())
          .build());
  ```

  ```php PHP
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          [
              'type' => 'user.message',
              'content' => [
                  [
                      'type' => 'text',
                      'text' => 'Analyze the performance of the sort function in utils.py',
                  ],
              ],
          ],
      ],
  );
  ```

  ```ruby Ruby
  client.beta.sessions.events.send_(
    session.id,
    events: [
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Analyze the performance of the sort function in utils.py"
          }
        ]
      }
    ]
  )
  ```
</CodeGroup>

Jedes Event im Verlauf der Session enthält einen `processed_at` (java, php: `processedAt`; csharp, go: `ProcessedAt`)-Zeitstempel, der gesetzt wird, wenn die Verarbeitung des Events abgeschlossen ist. Bei Events, die du sendest, ist `processed_at` (java, php: `processedAt`; csharp, go: `ProcessedAt`) `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `time.Time{}`), solange das Event noch hinter früheren Events in der Warteschlange steht. Ausnahmen sind `user.define_outcome`, `user.custom_tool_result` und `user.tool_result`, die beim Empfang verarbeitet und mit bereits befülltem `processed_at` (java, php: `processedAt`; csharp, go: `ProcessedAt`) zurückgegeben werden.

## Reagieren, wenn die Session in den Leerlauf geht

Ein `session.status_idle`-Event bedeutet, dass der Agent angehalten hat und auf eine Eingabe wartet. Sein `stop_reason.type` gibt den Grund an:

| `stop_reason.type` | Warum die Session angehalten hat                                                                                                                                 | Was zu tun ist                                                                                                                                                            |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `end_turn`         | Der Agent hat seinen Turn beendet, oder [du hast ihn unterbrochen](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#interrupt-the-agent). | [Sende eine `user.message`](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#resume-an-idle-session), wenn du weitere Arbeit für den Agenten hast. |
| `requires_action`  | Ein oder mehrere Tool-Aufrufe benötigen eine Antwort von dir, etwa ein Custom-Tool-Aufruf oder eine Bestätigungsanfrage.                                         | [Beantworte jeden blockierenden Tool-Aufruf](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session).           |
| `budget_reached`   | Die erfassten Listenkosten der Session haben ihr [Budget](https://platform.claude.com/docs/de/managed-agents/budgets) erreicht.                                  | [Ändere oder entferne das Budget](https://platform.claude.com/docs/de/managed-agents/budgets#resume-a-session-at-its-budget).                                             |

Kein Event, das du sendest, setzt eine Session fort, die an ihrem Budget pausiert ist. Die durch das Budget pausierte Arbeit wird automatisch fortgesetzt, wenn du das Budget auf einen Wert oberhalb der verbrauchten Listenkosten änderst oder es entfernst. Wenn die Arbeit fortgesetzt wird, gibt die Session für jeden [durch das Budget pausierten Workflow-Run](https://platform.claude.com/docs/de/managed-agents/workflow-runs#budgets-and-limits) ein `workflow_run.status_running`-Event aus. Ein durch einen Interrupt pausierter Run bleibt pausiert; siehe [Eine Session an ihrem Budget fortsetzen](https://platform.claude.com/docs/de/managed-agents/budgets#resume-a-session-at-its-budget). Unter [Wenn eine Session ihr Budget erreicht](https://platform.claude.com/docs/de/managed-agents/budgets#when-a-session-reaches-its-budget) findest du die Events, die die Pause markieren, und die Events, die die Session weiterhin akzeptiert.

## Tool-Aufrufe beantworten, die die Session pausieren

Eine Session pausiert, wenn der Agent ein [Custom Tool](https://platform.claude.com/docs/de/managed-agents/tools#custom-tools) aufruft und wenn ein Tool-Aufruf gemäß einer [Permission Policy](https://platform.claude.com/docs/de/managed-agents/permission-policies) deine Bestätigung benötigt. Beide Pausen folgen demselben Ablauf:

1. Die Session gibt den Tool-Aufruf als `agent.custom_tool_use`-, `agent.tool_use`- oder `agent.mcp_tool_use`-Event aus.
2. Die Session pausiert mit einem `session.status_idle`-Event, dessen `stop_reason.type` `requires_action` ist. Die IDs der blockierenden Events stehen im Array `stop_reason.event_ids`.
3. Sende für jede blockierende Event-ID ein [`user.custom_tool_result`](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#return-a-custom-tool-result)- oder ein [`user.tool_confirmation`](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#confirm-a-tool-call)-Event. Ein Custom-Tool-Ergebnis muss nicht auf Schritt 2 warten.
4. Sobald alle blockierenden Events aufgelöst sind, wechselt die Session zurück zu `running`.

In einer Multiagent-Session werden die blockierenden Events eines Subagenten zusätzlich im primären Thread veröffentlicht. Siehe [Tool-Berechtigungen und Custom Tools](https://platform.claude.com/docs/de/managed-agents/session-threads#tool-permissions-and-custom-tools).

### Ein Custom-Tool-Ergebnis zurückgeben

Das `agent.custom_tool_use`-Event enthält den Tool-Namen und die Eingabe. Führe das Tool in deinem System aus. Sende dann ein `user.custom_tool_result`-Event und übergib die Event-ID im Parameter `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`) zusammen mit dem Ergebnisinhalt.

Du kannst das Ergebnis senden, sobald das `agent.custom_tool_use`-Event eintrifft, ohne auf `session.status_idle` zu warten. Die Session gibt für den Aufruf trotzdem `session.status_idle` mit dem Stop-Grund `requires_action` aus, und dein Client kann es ignorieren. Ein zweites Ergebnis für denselben Aufruf wird akzeptiert und hat keine Wirkung.

Wenn du dich erneut mit einer pausierten Session [verbindest](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#reconnect-without-missing-events), listet `stop_reason.event_ids` im neuesten `session.status_idle`-Event die zu beantwortenden Aufrufe auf.

Das folgende Beispiel beantwortet jeden Aufruf, sobald er eintrifft:

<CodeGroup exclude="shell:cURL, shell:CLI">
  <CodeGroupItem language="cURL">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  ```python Python
  with client.beta.sessions.events.stream(session.id) as stream:
      for event in stream:
          match event.type:
              case "agent.custom_tool_use":
                  # Tool ausführen
                  result = call_tool(event.name, event.input)

                  # Ergebnis zurücksenden
                  client.beta.sessions.events.send(
                      session.id,
                      events=[
                          {
                              "type": "user.custom_tool_result",
                              "custom_tool_use_id": event.id,
                              "content": [{"type": "text", "text": result}],
                          },
                      ],
                  )
              case "session.status_idle":
                  if event.stop_reason and event.stop_reason.type == "end_turn":
                      break
  ```

  ```typescript TypeScript
  const stream = await client.beta.sessions.events.stream(session.id);

  loop: for await (const event of stream) {
    switch (event.type) {
      case "agent.custom_tool_use": {
        // Tool ausführen
        const result = await callTool(event.name, event.input);

        // Ergebnis zurücksenden
        await client.beta.sessions.events.send(session.id, {
          events: [
            {
              type: "user.custom_tool_result",
              custom_tool_use_id: event.id,
              content: [{ type: "text", text: result }]
            }
          ]
        });
        break;
      }
      case "session.status_idle":
        if (event.stop_reason.type === "end_turn") {
          break loop;
        }
        break;
    }
  }
  ```

  ```csharp C#
  await foreach (var streamEvent in client.Beta.Sessions.Events.StreamStreaming(session.ID))
  {
      if (streamEvent.Value is BetaManagedAgentsAgentCustomToolUseEvent toolUse)
      {
          // Tool ausführen
          var result = await CallTool(toolUse.Name, toolUse.Input);

          // Ergebnis zurücksenden
          await client.Beta.Sessions.Events.Send(session.ID, new()
          {
              Events =
              [
                  new BetaManagedAgentsUserCustomToolResultEventParams
                  {
                      Type = BetaManagedAgentsUserCustomToolResultEventParamsType.UserCustomToolResult,
                      CustomToolUseID = toolUse.ID,
                      Content =
                      [
                          new BetaManagedAgentsTextBlock
                          {
                              Type = BetaManagedAgentsTextBlockType.Text,
                              Text = result,
                          },
                      ],
                  },
              ],
          });
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent idle
          && idle.StopReason?.Value is BetaManagedAgentsSessionEndTurn)
      {
          break;
      }
  }
  ```

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

  loop:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsAgentCustomToolUseEvent:
  			// Tool ausführen
  			result := callTool(event.Name, event.Input)
  			// Ergebnis zurücksenden
  			if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, 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 {
  				panic(err)
  			}
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			if _, ok := event.StopReason.AsAny().(anthropic.BetaManagedAgentsSessionEndTurn); ok {
  				break loop
  			}
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
      loop:
      for (var event : (Iterable<BetaManagedAgentsStreamSessionEvents>) stream.stream()::iterator) {
          switch (event.type().value()) {
              case AGENT_CUSTOM_TOOL_USE -> {
                  // Tool ausführen
                  var toolUse = event.asAgentCustomToolUse();
                  var result = callTool(toolUse.name(), toolUse.input());

                  // Ergebnis zurücksenden
                  client.beta().sessions().events().send(
                      session.id(),
                      EventSendParams.builder()
                          .addEvent(BetaManagedAgentsUserCustomToolResultEventParams.builder()
                              .type(BetaManagedAgentsUserCustomToolResultEventParams.Type.USER_CUSTOM_TOOL_RESULT)
                              .customToolUseId(toolUse.id())
                              .addTextContent(result)
                              .build())
                          .build());
              }
              case SESSION_STATUS_IDLE -> {
                  if (event.asSessionStatusIdle().stopReason().isEndTurn()) {
                      break loop;
                  }
              }
          }
      }
  }
  ```

  ```php PHP
  $stream = $client->beta->sessions->events->streamStream($session->id);

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentCustomToolUseEvent:
              // Tool ausführen
              $result = callTool($event->name, $event->input);

              // Ergebnis zurücksenden
              $client->beta->sessions->events->send(
                  $session->id,
                  events: [
                      [
                          'type' => 'user.custom_tool_result',
                          'custom_tool_use_id' => $event->id,
                          'content' => [['type' => 'text', 'text' => $result]],
                      ],
                  ],
              );
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent:
              if ($event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionEndTurn) {
                  break 2;
              }
              break;
      }
  }
  ```

  ```ruby Ruby
  client.beta.sessions.events.stream_events(session.id).each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentCustomToolUseEvent
      # Tool ausführen
      result = call_tool.call(event.name, event.input)
      # Ergebnis zurücksenden
      client.beta.sessions.events.send_(
        session.id,
        events: [
          {
            type: "user.custom_tool_result",
            custom_tool_use_id: event.id,
            content: [{type: "text", text: result}]
          }
        ]
      )
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      break if event.stop_reason.is_a?(Anthropic::Beta::Sessions::BetaManagedAgentsSessionEndTurn)
    end
  end
  ```
</CodeGroup>

Wenn der Agent offene [Workflow-Runs](https://platform.claude.com/docs/de/managed-agents/workflow-runs) hat, kann ein Custom-Tool-Aufruf eintreffen, während die Session `running` bleibt. Das `requires_action`-Leerlauf-Event trifft erst ein, wenn keiner der [Threads der Session](https://platform.claude.com/docs/de/managed-agents/session-threads) arbeitet. Warte nicht darauf: Beantworte jeden Aufruf, wenn sein `agent.custom_tool_use`-Event eintrifft. Das Beispiel unter [Einen Run verfolgen](https://platform.claude.com/docs/de/managed-agents/workflow-runs#follow-a-run) zeigt, wie das geht.

### Einen Tool-Aufruf bestätigen

Sende ein `user.tool_confirmation`-Event und übergib die Event-ID im Parameter `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`). Setze `result` (csharp, go: `Result`) auf `"allow"` oder `"deny"`. Unter [Auf Bestätigungsanfragen reagieren](https://platform.claude.com/docs/de/managed-agents/permission-policies#respond-to-confirmation-requests) erfährst du, welche Aufrufe auf eine Bestätigung warten und wie du eine Ablehnung begründest.

Das folgende Beispiel genehmigt jeden ausstehenden Aufruf:

<CodeGroup exclude="shell:cURL, shell:CLI">
  <CodeGroupItem language="cURL">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Dieser Workflow erfordert mehr Logik als ein einzelner Shell-Befehl. Verwende das [Claude SDK](https://platform.claude.com/docs/de/cli-sdks-libraries/overview), um ihn auszuführen.
  </CodeGroupItem>

  ```python Python
  with client.beta.sessions.events.stream(session.id) as stream:
      for event in stream:
          if event.type == "session.status_idle" and (stop_reason := event.stop_reason):
              match stop_reason.type:
                  case "requires_action":
                      for event_id in stop_reason.event_ids:
                          # Genehmige den ausstehenden Tool-Aufruf
                          client.beta.sessions.events.send(
                              session.id,
                              events=[
                                  {
                                      "type": "user.tool_confirmation",
                                      "tool_use_id": event_id,
                                      "result": "allow",
                                  },
                              ],
                          )
                  case "end_turn":
                      break
  ```

  ```typescript TypeScript
  const stream = await client.beta.sessions.events.stream(session.id);

  for await (const event of stream) {
    if (event.type !== "session.status_idle") {
      continue;
    }
    if (event.stop_reason.type === "end_turn") {
      break;
    }
    if (event.stop_reason.type !== "requires_action") {
      continue;
    }

    for (const eventId of event.stop_reason.event_ids) {
      // Genehmige den ausstehenden Tool-Aufruf
      await client.beta.sessions.events.send(session.id, {
        events: [
          {
            type: "user.tool_confirmation",
            tool_use_id: eventId,
            result: "allow"
          }
        ]
      });
    }
  }
  ```

  ```csharp C#
  await foreach (var streamEvent in client.Beta.Sessions.Events.StreamStreaming(session.ID))
  {
      if (streamEvent.Value is not BetaManagedAgentsSessionStatusIdleEvent idle) continue;

      if (idle.StopReason?.Value is BetaManagedAgentsSessionRequiresAction requiresAction)
      {
          foreach (var eventId in requiresAction.EventIds)
          {
              // Genehmige den ausstehenden Tool-Aufruf
              await client.Beta.Sessions.Events.Send(session.ID, new()
              {
                  Events =
                  [
                      new BetaManagedAgentsUserToolConfirmationEventParams
                      {
                          Type = BetaManagedAgentsUserToolConfirmationEventParamsType.UserToolConfirmation,
                          ToolUseID = eventId,
                          Result = BetaManagedAgentsUserToolConfirmationEventParamsResult.Allow,
                      },
                  ],
              });
          }
      }
      else if (idle.StopReason?.Value is BetaManagedAgentsSessionEndTurn)
      {
          break;
      }
  }
  ```

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

  loop:
  	for stream.Next() {
  		event, ok := stream.Current().AsAny().(anthropic.BetaManagedAgentsSessionStatusIdleEvent)
  		if !ok {
  			continue
  		}
  		switch stopReason := event.StopReason.AsAny().(type) {
  		case anthropic.BetaManagedAgentsSessionRequiresAction:
  			for _, eventID := range stopReason.EventIDs {
  				// Den ausstehenden Tool-Aufruf genehmigen
  				if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  					Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  						OfUserToolConfirmation: &anthropic.BetaManagedAgentsUserToolConfirmationEventParams{
  							Type:      anthropic.BetaManagedAgentsUserToolConfirmationEventParamsTypeUserToolConfirmation,
  							ToolUseID: eventID,
  							Result:    anthropic.BetaManagedAgentsUserToolConfirmationEventParamsResultAllow,
  						},
  					}},
  				}); err != nil {
  					panic(err)
  				}
  			}
  		case anthropic.BetaManagedAgentsSessionEndTurn:
  			break loop
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  try (var stream = client.beta().sessions().events().streamStreaming(session.id())) {
      stream.stream()
          .filter(BetaManagedAgentsStreamSessionEvents::isSessionStatusIdle)
          .map(idleEvent -> idleEvent.asSessionStatusIdle().stopReason())
          .takeWhile(stopReason -> !stopReason.isEndTurn())
          .filter(stopReason -> stopReason.isRequiresAction())
          .flatMap(stopReason -> stopReason.asRequiresAction().eventIds().stream())
          // Genehmige jeden ausstehenden Tool-Aufruf
          .forEach(toolUseId -> client.beta().sessions().events().send(
              session.id(),
              EventSendParams.builder()
                  .addEvent(BetaManagedAgentsUserToolConfirmationEventParams.builder()
                      .type(BetaManagedAgentsUserToolConfirmationEventParams.Type.USER_TOOL_CONFIRMATION)
                      .toolUseId(toolUseId)
                      .result(BetaManagedAgentsUserToolConfirmationEventParams.Result.ALLOW)
                      .build())
                  .build()));
  }
  ```

  ```php PHP
  $stream = $client->beta->sessions->events->streamStream($session->id);

  foreach ($stream as $event) {
      if ($event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent && $event->stopReason) {
          switch (true) {
              case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionRequiresAction:
                  foreach ($event->stopReason->eventIDs as $eventId) {
                      // Ausstehenden Tool-Aufruf genehmigen
                      $client->beta->sessions->events->send(
                          $session->id,
                          events: [
                              [
                                  'type' => 'user.tool_confirmation',
                                  'tool_use_id' => $eventId,
                                  'result' => 'allow',
                              ],
                          ],
                      );
                  }
                  break;
              case $event->stopReason instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionEndTurn:
                  break 2;
          }
      }
  }
  ```

  ```ruby Ruby
  client.beta.sessions.events.stream_events(session.id).each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      stop_reason = event.stop_reason
      case stop_reason
      when Anthropic::Beta::Sessions::BetaManagedAgentsSessionRequiresAction
        stop_reason.event_ids.each do |event_id|
          # Genehmige den ausstehenden Tool-Aufruf
          client.beta.sessions.events.send_(
            session.id,
            events: [
              {type: "user.tool_confirmation", tool_use_id: event_id, result: "allow"}
            ]
          )
        end
      when Anthropic::Beta::Sessions::BetaManagedAgentsSessionEndTurn
        break
      end
    end
  end
  ```
</CodeGroup>

Das vorherige Beispiel genehmigt jeden Aufruf, nachdem die Session in den Leerlauf gegangen ist. Wenn der Agent offene [Workflow-Runs](https://platform.claude.com/docs/de/managed-agents/workflow-runs) hat, kann ein Tool-Aufruf auf deine Bestätigung warten, während die Session `running` bleibt. Warte nicht auf das Leerlauf-Event: Wenn ein `agent.tool_use`- oder `agent.mcp_tool_use`-Event eintrifft, dessen [`evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`)](https://platform.claude.com/docs/de/managed-agents/permission-policies#see-how-each-call-was-evaluated) `ask` ist, beantworte es. Das Beispiel unter [Einen Run verfolgen](https://platform.claude.com/docs/de/managed-agents/workflow-runs#follow-a-run) beantwortet Custom-Tool-Aufrufe auf diese Weise, und seine Einleitung erklärt, wie du Bestätigungen hinzufügst.

## Eine Session im Leerlauf fortsetzen

Sessions bleiben zwischen Interaktionen bestehen. Um eine Session fortzusetzen, sende ihr wie gewohnt ein `user.message`-Event:

<CodeGroup>
  ```bash cURL
  # In Produktion übergib die gespeicherte ID der Session, die du fortsetzen willst.
  curl --fail-with-body -sS "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.message",
          "content": [
            {"type": "text", "text": "Now run the tests against the changes you made earlier."}
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  # In Produktion übergib die gespeicherte ID der Session, die du fortsetzen willst.
  ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
  events:
    - type: user.message
      content:
        - type: text
          text: Now run the tests against the changes you made earlier.
  YAML
  ```

  ```python Python
  # Setze eine zuvor erstellte Session fort, indem du ihr ein neues user.message-Event sendest.
  # In Produktion übergibst du die gespeicherte ID der Session, die du fortsetzen möchtest.
  client.beta.sessions.events.send(
      session.id,
      events=[
          {
              "type": "user.message",
              "content": [
                  {
                      "type": "text",
                      "text": "Now run the tests against the changes you made earlier.",
                  },
              ],
          },
      ],
  )
  ```

  ```typescript TypeScript
  // Setze eine zuvor erstellte Session fort, indem du ihr ein neues User-Event sendest.
  // In Produktion übergib die gespeicherte ID der Session, die du fortsetzen möchtest.
  await client.beta.sessions.events.send(session.id, {
    events: [
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Now run the tests against the changes you made earlier."
          }
        ]
      }
    ]
  });
  ```

  ```csharp C#
  // Setze eine zuvor erstellte Session per ID fort. In Produktion übergib die
  // Session-ID, die du beim Erstellen der Session gespeichert hast.
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Now run the tests against the changes you made earlier.",
                  },
              ],
          },
      ],
  });
  ```

  ```go Go
  // Eine zuvor erstellte Session fortsetzen, indem ihr ein neues user.message-Event
  // gesendet wird. In Produktion die gespeicherte ID der fortzusetzenden Session übergeben.
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  		OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  			Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  			Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  				OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  					Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  					Text: "Now run the tests against the changes you made earlier.",
  				},
  			}},
  		},
  	}},
  }); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  // Setze eine zuvor erstellte Session per ID fort. In Produktion übergibst du die
  // Session-ID, die du beim Erstellen der Session gespeichert hast.
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
              .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
              .addTextContent("Now run the tests against the changes you made earlier.")
              .build())
          .build());
  ```

  ```php PHP
  // Setze eine zuvor erstellte Session fort, indem du ihr ein neues user.message-Event sendest.
  // Übergib in Produktion die Session-ID, die du beim Erstellen der Session gespeichert hast.
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          [
              'type' => 'user.message',
              'content' => [
                  [
                      'type' => 'text',
                      'text' => 'Now run the tests against the changes you made earlier.',
                  ],
              ],
          ],
      ],
  );
  ```

  ```ruby Ruby
  # Eine Session fortzusetzen heißt einfach, ihr das nächste Event zu senden. In Produktion
  # übergib die Session-ID, die du beim Erstellen der Session gespeichert hast.
  client.beta.sessions.events.send_(
    session.id,
    events: [
      {
        type: "user.message",
        content: [
          {type: "text", text: "Now run the tests against the changes you made earlier."}
        ]
      }
    ]
  )
  ```
</CodeGroup>

Der Gesprächsverlauf bleibt erhalten, sofern die Session nicht explizit gelöscht wird. Wenn eine Session in den Leerlauf geht, wird für ihre Sandbox ein Checkpoint erstellt. Der Checkpoint bewahrt den vollständigen Sandbox-Zustand, einschließlich des Dateisystems, installierter Pakete und aller Dateien, die der Agent erstellt hat.

<Note>
  Der Sandbox-Zustand bleibt nur 30 Tage nach Erstellung der Sandbox erhalten, und Aktivität verlängert dieses Zeitfenster nicht. Nach 30 Tagen ist der Sandbox-Zustand (Dateien, installierte Tools usw.) nicht wiederherstellbar, und eine fortgesetzte Session startet mit einer neuen Sandbox. Wenn dein Workflow von Sandbox-Inhalten abhängt, lass den Agenten wichtige Artefakte in [Outputs](https://platform.claude.com/docs/de/managed-agents/define-outcomes#retrieving-deliverables) schreiben, bevor das Zeitfenster endet.
</Note>

## Den Agenten unterbrechen

Sende ein `user.interrupt`-Event, um den Agenten während der Ausführung anzuhalten, und sende anschließend ein `user.message`-Event, um ihn umzulenken:

<CodeGroup>
  ```bash cURL
  # Agent analysiert gerade eine Datei...
  # Unterbrich mit einer neuen Anweisung:
  curl --fail-with-body -sS "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"},
        {
          "type": "user.message",
          "content": [
            {"type": "text", "text": "Instead, focus on fixing the bug in line 42."}
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  # Agent analysiert gerade eine Datei...
  # Unterbrich mit einer neuen Anweisung:
  ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
  events:
    - type: user.interrupt
    - type: user.message
      content:
        - type: text
          text: Instead, focus on fixing the bug in line 42.
  YAML
  ```

  ```python Python
  # Agent analysiert gerade eine Datei...
  # Unterbrich mit einer neuen Anweisung:
  client.beta.sessions.events.send(
      session.id,
      events=[
          {"type": "user.interrupt"},
          {
              "type": "user.message",
              "content": [
                  {
                      "type": "text",
                      "text": "Instead, focus on fixing the bug in line 42.",
                  },
              ],
          },
      ],
  )
  ```

  ```typescript TypeScript
  // Agent analysiert gerade eine Datei...
  // Unterbrich mit einer neuen Anweisung:
  await client.beta.sessions.events.send(session.id, {
    events: [
      { type: "user.interrupt" },
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Instead, focus on fixing the bug in line 42."
          }
        ]
      }
    ]
  });
  ```

  ```csharp C#
  // Agent analysiert gerade eine Datei...
  // Unterbrich mit einer neuen Richtung:
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserInterruptEventParams
          {
              Type = BetaManagedAgentsUserInterruptEventParamsType.UserInterrupt,
          },
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Instead, focus on fixing the bug in line 42.",
                  },
              ],
          },
      ],
  });
  ```

  ```go Go
  // Agent analysiert gerade eine Datei...
  // Mit einer neuen Anweisung unterbrechen:
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{
  		{
  			OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{
  				Type: anthropic.BetaManagedAgentsUserInterruptEventParamsTypeUserInterrupt,
  			},
  		},
  		{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  						Text: "Instead, focus on fixing the bug in line 42.",
  					},
  				}},
  			},
  		},
  	},
  }); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  // Agent analysiert gerade eine Datei...
  // Mit einer neuen Richtung unterbrechen:
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsUserInterruptEventParams.builder()
              .type(BetaManagedAgentsUserInterruptEventParams.Type.USER_INTERRUPT)
              .build())
          .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
              .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
              .addTextContent("Instead, focus on fixing the bug in line 42.")
              .build())
          .build());
  ```

  ```php PHP
  // Agent analysiert gerade eine Datei...
  // Mit einer neuen Anweisung unterbrechen:
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          ['type' => 'user.interrupt'],
          [
              'type' => 'user.message',
              'content' => [
                  [
                      'type' => 'text',
                      'text' => 'Instead, focus on fixing the bug in line 42.',
                  ],
              ],
          ],
      ],
  );
  ```

  ```ruby Ruby
  # Agent analysiert gerade eine Datei...
  # Unterbrich mit einer neuen Anweisung:
  client.beta.sessions.events.send_(
    session.id,
    events: [
      {type: "user.interrupt"},
      {
        type: "user.message",
        content: [
          {type: "text", text: "Instead, focus on fixing the bug in line 42."}
        ]
      }
    ]
  )
  ```
</CodeGroup>

Der Aufruf kehrt zurück, sobald die Events in die Warteschlange gestellt sind. Der Interrupt wird dann in dieser Reihenfolge wirksam:

1. Der Agent wendet den Interrupt an. Bis dahin bleibt `processed_at` (java, php: `processedAt`; csharp, go: `ProcessedAt`) des Interrupts `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `time.Time{}`), und die Session bleibt `running`. Eine laufende Modellantwort stoppt sofort, aber das Anwenden des Interrupts kann länger dauern, während Tool-Aufrufe laufen.
2. Das `user.interrupt`-Event erscheint im Stream, und der unterbrochene Turn endet mit einem `session.status_idle`-Event.
3. Der Agent beginnt seinen nächsten Turn mit der `user.message`, die du nach dem Interrupt gesendet hast.

Der `stop_reason.type` des Leerlauf-Events ist `end_turn`, derselbe Wert wie bei einem Turn, der von selbst endet. Wenn Workflow-Runs offen sind, beendet der Interrupt keinen davon. Ein laufender Run kann die Session auf `running` halten, sodass das `session.status_idle`-Event in Schritt 2 möglicherweise nicht eintrifft. Siehe [Eine Session mit offenen Runs unterbrechen](https://platform.claude.com/docs/de/managed-agents/workflow-runs#interrupt-a-session-with-runs-open).

## Vergangene Events auflisten

Rufe den vollständigen Event-Verlauf einer Session ab:

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS "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"
  ```

  ```bash CLI
  ant beta:sessions:events list --session-id "$SESSION_ID" --format jsonl
  ```

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

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

  ```csharp C#
  var events = await client.Beta.Sessions.Events.List(session.ID);
  foreach (var sessionEvent in events.Items)
  {
      Console.WriteLine($"[{sessionEvent.Json.GetProperty("type").GetString()}] {sessionEvent.ProcessedAt}");
  }
  ```

  ```go Go
  events, err := client.Beta.Sessions.Events.List(ctx, session.ID, anthropic.BetaSessionEventListParams{})
  if err != nil {
  	panic(err)
  }
  for _, event := range events.Data {
  	fmt.Printf("[%s] %s\n", event.Type, event.ProcessedAt)
  }
  ```

  ```java Java
  var events = client.beta().sessions().events().list(session.id());
  for (var event : events.data()) {
      var eventJson = event._json().orElseThrow().convert(JsonNode.class);
      var processedAt = eventJson.path("processed_at");
      IO.println("[" + eventJson.get("type").asText() + "] "
          + (processedAt.isTextual() ? processedAt.asText() : "null"));
  }
  ```

  ```php PHP
  $events = $client->beta->sessions->events->list($session->id);
  foreach ($events->data as $event) {
      $processedAt = ($event->processedAt ?? null)?->format(DATE_RFC3339) ?? 'null';
      echo "[{$event->type}] {$processedAt}\n";
  }
  ```

  ```ruby Ruby
  events = client.beta.sessions.events.list(session.id)
  events.data.each { puts "[#{it.type}] #{it.processed_at}" }
  ```
</CodeGroup>

Übergib einen `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`)-Filter, um nur bestimmte Event-Typen zurückzugeben:

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true&types[]=agent.tool_use&types[]=agent.tool_result" \
    -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 list --session-id "$SESSION_ID" \
    --type agent.tool_use --type agent.tool_result \
    --format jsonl
  ```

  ```python Python
  events = client.beta.sessions.events.list(
      session.id,
      types=["agent.tool_use", "agent.tool_result"],
  )
  for event in events.data:
      print(f"[{event.type}] {event.processed_at}")
  ```

  ```typescript TypeScript
  const events = await client.beta.sessions.events.list(session.id, {
    types: ["agent.tool_use", "agent.tool_result"]
  });
  for (const event of events.data) {
    console.log(`[${event.type}] ${event.processed_at}`);
  }
  ```

  ```csharp C#
  var events = await client.Beta.Sessions.Events.List(session.ID, new()
  {
      Types = ["agent.tool_use", "agent.tool_result"],
  });
  foreach (var sessionEvent in events.Items)
  {
      Console.WriteLine($"[{sessionEvent.Json.GetProperty("type").GetString()}] {sessionEvent.ProcessedAt}");
  }
  ```

  ```go Go
  events, err := client.Beta.Sessions.Events.List(ctx, session.ID, anthropic.BetaSessionEventListParams{
  	Types: []anthropic.BetaManagedAgentsSessionEventType{
  		anthropic.BetaManagedAgentsSessionEventTypeAgentToolUse,
  		anthropic.BetaManagedAgentsSessionEventTypeAgentToolResult,
  	},
  })
  if err != nil {
  	panic(err)
  }
  for _, event := range events.Data {
  	fmt.Printf("[%s] %s\n", event.Type, event.ProcessedAt)
  }
  ```

  ```java Java
  var events = client.beta().sessions().events().list(
      session.id(),
      EventListParams.builder()
          .addType(BetaManagedAgentsSessionEventType.AGENT_TOOL_USE)
          .addType(BetaManagedAgentsSessionEventType.AGENT_TOOL_RESULT)
          .build());
  for (var event : events.data()) {
      event.agentToolUse().ifPresent(toolUse ->
          IO.println("[" + toolUse.type() + "] " + toolUse.processedAt()));
      event.agentToolResult().ifPresent(toolResult ->
          IO.println("[" + toolResult.type() + "] " + toolResult.processedAt()));
  }
  ```

  ```php PHP
  $events = $client->beta->sessions->events->list(
      $session->id,
      types: ['agent.tool_use', 'agent.tool_result'],
  );
  foreach ($events->data as $event) {
      $processedAt = ($event->processedAt ?? null)?->format(DATE_RFC3339) ?? 'null';
      echo "[{$event->type}] {$processedAt}\n";
  }
  ```

  ```ruby Ruby
  events = client.beta.sessions.events.list(
    session.id,
    types: ["agent.tool_use", "agent.tool_result"]
  )
  events.data.each { puts "[#{it.type}] #{it.processed_at}" }
  ```
</CodeGroup>

## System-Nachrichten senden

Sende auf einem [unterstützten Modell](https://platform.claude.com/docs/de/managed-agents/events-and-streaming#supported-models) ein `system.message`-Event, um dem Agenten privilegierten Kontext auf Systemebene zu geben. Der Kontext gilt für den zugehörigen Turn und alle nachfolgenden Turns. Verwende es, wenn der Agent mitten in der Session aktualisierte Anweisungen auf Systemebene benötigt, zum Beispiel eine andere Persona, überarbeitete Einschränkungen oder zur Laufzeit abgerufenen Kontext.

Das Feld `content` (csharp, go: `Content`) des Events akzeptiert 1–1000 Text-Elemente. Der Inhalt wird als `role: "system"`-Turn an den Systemkontext der Session angehängt. Er ersetzt nicht den übergeordneten „system prompt" (System-Prompt), den das Feld `system` (csharp, go: `System`; ruby: `system_`) in der Agent-Definition festlegt.

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS "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": "system.message",
          "content": [
            {"type": "text", "text": "The current timezone of the user is America/New_York."}
          ]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
  events:
    - type: system.message
      content:
        - type: text
          text: "The user's current timezone is America/New_York."
  YAML
  ```

  ```python Python
  client.beta.sessions.events.send(
      session.id,
      events=[
          {
              "type": "system.message",
              "content": [
                  {
                      "type": "text",
                      "text": "The user's current timezone is America/New_York.",
                  },
              ],
          },
      ],
  )
  ```

  ```typescript TypeScript
  await client.beta.sessions.events.send(session.id, {
    events: [
      {
        type: "system.message",
        content: [
          {
            type: "text",
            text: "The user's current timezone is America/New_York."
          }
        ]
      }
    ]
  });
  ```

  ```csharp C#
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsSystemMessageEventParams
          {
              Type = BetaManagedAgentsSystemMessageEventParamsType.SystemMessage,
              Content =
              [
                  new BetaManagedAgentsSystemContentBlock
                  {
                      Type = BetaManagedAgentsSystemContentBlockType.Text,
                      Text = "The user's current timezone is America/New_York.",
                  },
              ],
          },
      ],
  });
  ```

  ```go Go
  if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  		OfSystemMessage: &anthropic.BetaManagedAgentsSystemMessageEventParams{
  			Type: anthropic.BetaManagedAgentsSystemMessageEventParamsTypeSystemMessage,
  			Content: []anthropic.BetaManagedAgentsSystemContentBlockParam{{
  				Type: anthropic.BetaManagedAgentsSystemContentBlockTypeText,
  				Text: "The user's current timezone is America/New_York.",
  			}},
  		},
  	}},
  }); err != nil {
  	panic(err)
  }
  ```

  ```java Java
  client.beta().sessions().events().send(
      session.id(),
      EventSendParams.builder()
          .addEvent(BetaManagedAgentsSystemMessageEventParams.builder()
              .type(BetaManagedAgentsSystemMessageEventParams.Type.SYSTEM_MESSAGE)
              .addTextContent("The user's current timezone is America/New_York.")
              .build())
          .build());
  ```

  ```php PHP
  $client->beta->sessions->events->send(
      $session->id,
      events: [
          [
              'type' => 'system.message',
              'content' => [
                  [
                      'type' => 'text',
                      'text' => "The user's current timezone is America/New_York.",
                  ],
              ],
          ],
      ],
  );
  ```

  ```ruby Ruby
  client.beta.sessions.events.send_(
    session.id,
    events: [
      {
        type: "system.message",
        content: [
          {type: "text", text: "The user's current timezone is America/New_York."}
        ]
      }
    ]
  )
  ```
</CodeGroup>

### Unterstützte Modelle

`system.message` wird von diesen Modellen unterstützt:

* Claude Fable 5.1
* Claude Mythos 5.1
* Claude Fable 5
* Claude Mythos 5
* Claude Opus 5.5
* Claude Opus 5
* Claude Opus 4.8
* Claude Sonnet 5.5
* Claude Haiku 5.5

Wenn das primäre Modell des Agenten keine System-Injektion mitten im Gespräch unterstützt, wird das Event mit dem Validierungsfehler `model_does_not_support_mid_conversation_system` abgelehnt. Subagent-Modelle werden nicht geprüft, da `system.message` nur im primären Thread landet.

### System-Nachrichten bei ausstehendem Tool-Aufruf

Während sich die Session mit dem Stop-Grund `requires_action` im Leerlauf befindet, muss eine `system.message` in derselben Anfrage auf ein Tool-Ergebnis-Event folgen. Allein oder zusammen mit einer `user.message` gesendet, wird sie abgelehnt, bis die ausstehenden Tool-Events aufgelöst sind.

## Nächste Schritte

<CardGroup cols={2}>
  <Card title="Antworten mit Event-Deltas vorab anzeigen" icon="text" href="https://platform.claude.com/docs/de/managed-agents/event-deltas">
    Stelle den Antworttext des Agenten dar, während das Modell ihn noch generiert.
  </Card>

  <Card title="Sessions untersuchen und Nutzung verfolgen" icon="magnifying-glass" href="https://platform.claude.com/docs/de/managed-agents/session-observability">
    Untersuche eine Session in der Claude Console und lies ihre Token-Nutzung und Listenkosten ab.
  </Card>

  <Card title="Webhooks abonnieren" icon="link" href="https://platform.claude.com/docs/de/managed-agents/webhooks">
    Lass dich ohne Polling benachrichtigen, wenn wichtige Events eintreten.
  </Card>

  <Card title="Event-Typen" icon="book" href="https://platform.claude.com/docs/de/managed-agents/reference#event-types">
    Schlage jeden Event-Typ nach, den eine Session senden oder empfangen kann.
  </Card>
</CardGroup>
