Claude Platform Docs
Managed AgentsArbeit an Ihren Agenten delegieren

Session-Event-Stream

Sende Events, streame Antworten und unterbrich oder lenke deine Session während der Ausführung um.

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-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 in der Referenz.

Webhook-Event-Typen 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.

# Ö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

Die Session meldet Fehler über das Event session.error. Seine Felder findest du unter Event-Typen.

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.

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, 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.
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

Events senden

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

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",
                },
            ],
        },
    ],
)

Jedes Event im Verlauf der Session enthält einen processed_at-Zeitstempel, der gesetzt wird, wenn die Verarbeitung des Events abgeschlossen ist. Bei Events, die du sendest, ist processed_at None, 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 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.typeWarum die Session angehalten hatWas zu tun ist
end_turnDer Agent hat seinen Turn beendet, oder du hast ihn unterbrochen.Sende eine user.message, wenn du weitere Arbeit für den Agenten hast.
requires_actionEin oder mehrere Tool-Aufrufe benötigen eine Antwort von dir, etwa ein Custom-Tool-Aufruf oder eine Bestätigungsanfrage.Beantworte jeden blockierenden Tool-Aufruf.
budget_reachedDie erfassten Listenkosten der Session haben ihr Budget erreicht.Ändere oder entferne das 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 ein workflow_run.status_running-Event aus. Ein durch einen Interrupt pausierter Run bleibt pausiert; siehe Eine Session an ihrem Budget fortsetzen. Unter Wenn eine Session ihr Budget erreicht 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 aufruft und wenn ein Tool-Aufruf gemäß einer Permission Policy 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- oder ein user.tool_confirmation-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.

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 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, 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:

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

Wenn der Agent offene 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 arbeitet. Warte nicht darauf: Beantworte jeden Aufruf, wenn sein agent.custom_tool_use-Event eintrifft. Das Beispiel unter Einen Run verfolgen 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. Setze result auf "allow" oder "deny". Unter Auf Bestätigungsanfragen reagieren erfährst du, welche Aufrufe auf eine Bestätigung warten und wie du eine Ablehnung begründest.

Das folgende Beispiel genehmigt jeden ausstehenden Aufruf:

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

Das vorherige Beispiel genehmigt jeden Aufruf, nachdem die Session in den Leerlauf gegangen ist. Wenn der Agent offene 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 ask ist, beantworte es. Das Beispiel unter Einen Run verfolgen 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:

# 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.",
                },
            ],
        },
    ],
)

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.

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:

# 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.",
                },
            ],
        },
    ],
)

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 des Interrupts None, 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.

Vergangene Events auflisten

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

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

Übergib einen types-Filter, um nur bestimmte Event-Typen zurückzugeben:

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}")

System-Nachrichten senden

Sende auf einem unterstützten Modell 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 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 in der Agent-Definition festlegt.

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

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

Stelle den Antworttext des Agenten dar, während das Modell ihn noch generiert.

Untersuche eine Session in der Claude Console und lies ihre Token-Nutzung und Listenkosten ab.

Lass dich ohne Polling benachrichtigen, wenn wichtige Events eintreten.

Schlage jeden Event-Typ nach, den eine Session senden oder empfangen kann.

Was this page helpful?