Claude Platform Docs
Managed AgentsErweiterte Orchestrierung

Session-Threads

Liste, unterbrich und archiviere die Threads einer Multiagenten-Session, lies ihre Events und verwalte Tool-Berechtigungen über sie hinweg.

In einer Multiagenten-Session arbeitet jeder Agent in seinem eigenen „session thread" (Session-Thread). Diese Seite behandelt, wie du Threads auflistest, unterbrichst und archivierst, welche Events sie senden und wie Tool-Berechtigungen über sie hinweg funktionieren. Ein Workflow-Run erstellt ebenfalls Session-Threads.

Primärer Thread und Session-Threads

Der Event-Stream auf Session-Ebene (/v1/sessions/{session_id}/events/stream) gilt als „primary thread" (primärer Thread) und enthält eine verdichtete Ansicht aller Aktivitäten über alle Threads hinweg. Du siehst nicht die vollständige Aktivität von Subagenten, aber du siehst den Beginn und das Ende ihrer Arbeit sowie blockierende Events wie Anfragen zu Tool-Berechtigungen.

In Session-Threads kannst du die Aktivität eines bestimmten Agenten im Detail untersuchen.

Der status der Session ist eine Aggregation aller Agentenaktivitäten; wenn mindestens ein Thread running ist, ist auch der Gesamtstatus der Session running. Ein laufender Workflow-Run kann die Session ebenfalls auf running halten, selbst wenn keiner seiner Threads arbeitet. Wenn kein Thread arbeitet und ein Thread auf deinen Client wartet, ist die Session idle; siehe Erkennen, wann die Arbeit erledigt ist.

Ein Session-Budget ist eine einzige gemeinsame Obergrenze für alle Threads einer Session. Wenn die Obergrenze erreicht wird, pausieren die Threads unabhängig voneinander, und die Kosten jedes Threads werden nach dem Modell berechnet, das diesen Thread bedient.

Threads auflisten

Liste alle Threads, die einer Session zugeordnet sind, wie folgt auf:

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

Die vollständige Liste enthält den primären Thread. parent_thread_id ist für den primären Thread null. Jeder andere Thread ist ein Kind-Thread. workflow_run_id ist null, außer bei den Threads eines Runs.

Um nur Threads mit bestimmten Status aufzulisten, füge der Anfrage statuses[] hinzu und wiederhole den Parameter, um mehr als einen Status anzugeben, wie in ?statuses[]=running&statuses[]=idle. Lass ihn weg, um Threads mit jedem Status zurückzugeben.

Einen Session-Thread unterbrechen

Sende user.interrupt mit session_thread_id, um einen bestimmten Thread zu stoppen. Wenn du session_thread_id weglässt, werden alle nicht archivierten Threads in der Session unterbrochen, einschließlich des primären. In einer Session mit dynamischen Workflows beendet eine Unterbrechung keinen Run, und eine Unterbrechung, die einen Thread eines Runs benennt, stoppt nichts. Eine Unterbrechung schließt ausstehende Tool-Aufrufe anderer Kind-Threads, aber verlass dich nicht darauf, dass sie die eines Run-Threads schließt. Siehe Eine Session mit offenen Runs unterbrechen.

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

Bei einem auf requires_action blockierten Thread eines Subagenten schließt die Unterbrechung jeden ausstehenden Tool-Aufruf mit einem Fehler-Tool-Ergebnis („Tool execution was interrupted before completion. Please retry.") und sendet session.thread_status_idle mit stop_reason: end_turn direkt erneut; das Modell wird nicht gesampelt. Bei einem Kind-Thread, der mit end_turn oder budget_reached inaktiv ist, hat die Unterbrechung keine Wirkung. Eine Unterbrechung, die einen beendeten Thread benennt, gibt einen 400-Fehler zurück. Ein unterbrochener Kind-Thread sendet dem Agenten des primären Threads nicht den Bericht, den er sendet, wenn ein Turn endet. Während dieser Agent auf den Kind-Thread wartet, beginnt er keinen weiteren Turn, bis ihn etwas anderes erreicht, etwa eine user.message oder der Bericht eines anderen Threads.

Einen Session-Thread archivieren

Archiviere einen Session-Thread optional, wenn er seine Arbeit abgeschlossen hat. Das Archivieren eines Threads gibt seinen Platz im Limit von 25 Kind-Threads frei. Der Server archiviert die Threads eines Workflow-Runs selbst. Du musst sie nicht archivieren, und du kannst es nicht, solange der Run offen ist.

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

Das Archivieren gelingt nur, wenn der Thread idle ist. Ein Thread, der auf requires_action wartet, gilt als inaktiv und kann direkt archiviert werden; nur ein laufender Thread muss zuerst unterbrochen werden:

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)

Events des primären Threads

Diese Events machen Multiagenten-Aktivität auf dem primären Thread unter /v1/sessions/{session_id}/events/stream sichtbar. Events mit Nachrichtenrichtung sind relativ zu dem Thread benannt, in dessen Stream sie erscheinen: agent.thread_message_received bedeutet, dass eine Nachricht von einem anderen Thread auf diesem Thread angekommen ist, und agent.thread_message_sent bedeutet, dass dieser Thread eine gesendet hat. Die Aufgabe, die der Agent des primären Threads delegiert, kommt beispielsweise im eigenen Stream des Kind-Threads als agent.thread_message_received-Event an.

TypBeschreibung
session.thread_createdEin Thread wurde erstellt. Enthält session_thread_id und agent_name.
session.thread_status_runningEin Thread hat eine Aktivität begonnen.
session.thread_status_idleDer dem Thread zugeordnete Agent wartet auf Eingabe. Enthält einen stop_reason, der angibt, warum der Agent angehalten hat.
session.thread_status_terminatedEin Thread wurde beendet und nimmt keine weiteren Eingaben an, zum Beispiel weil er archiviert wurde oder auf einen nicht behebbaren Fehler gestoßen ist. Ein Advisor-Thread wird ebenfalls beendet, wenn seine Konsultation endet.
agent.thread_message_receivedAuf dem primären Thread hat ein Subagent dem Agenten des primären Threads einen Bericht oder eine Frage gesendet. Enthält from_session_thread_id, from_agent_name und content.
agent.thread_message_sentAuf dem primären Thread hat der Agent des primären Threads einem Subagenten eine Aufgabe oder eine Folgenachricht gesendet. Enthält to_session_thread_id, to_agent_name und content.

Advisor-Konsultationen senden dieselben Thread-Events unter dem reservierten Namen anthropic.advisor (als agent_name bei den Thread-Lebenszyklus-Events und als from_agent_name bei der Übermittlung des Ratschlags); siehe Der Session einen Advisor geben für den Ablauf.

Die Threads eines Workflow-Runs erscheinen im primären Stream wie folgt:

  • Lebenszyklus-Events: Jeder Run-Thread sendet session.thread_created mit der workflow_run_id des Runs sowie seine Events session.thread_status_running, session.thread_status_idle und session.thread_status_terminated.
  • Nachrichten-Events: Der Prompt eines Run-Threads, ein agent.thread_message_received-Event, bleibt in dessen eigenem Stream.
  • Run-Events: workflow_run.*-Events kommen ebenfalls in diesem Stream an; siehe Run-Events.
  • Tool-Aufrufe, die auf dich warten: Tool-Aufrufe eines Run-Threads, die deinen Client benötigen, werden wie bei jedem Kind-Thread in diesen Stream gespiegelt. Siehe Tool-Berechtigungen und benutzerdefinierte Tools.

Session-Thread-Events

Kritische Events werden an den primären Thread weitergeleitet. Dennoch möchtest du vielleicht das Reasoning und die Tool-Aufrufe eines bestimmten Agenten untersuchen. Streame oder liste dazu die Events des zugehörigen Session-Threads auf.

Jeder Session-Thread hat seinen eigenen Event-Stream unter /v1/sessions/{session_id}/threads/{thread_id}/stream, und dieser akzeptiert denselben Parameter event_deltas[] wie der Stream auf Session-Ebene, sodass du den Text eines Subagenten in der Vorschau sehen kannst, während das Modell ihn generiert. Eine Verbindung zeigt nur Vorschauen für den Thread, den sie liest: Die Vorschauen eines Kind-Threads erscheinen nie im Stream auf Session-Ebene. Um einen Subagenten live zu verfolgen, öffne also seinen eigenen Thread-Stream. Unter Session-Thread-Events in der Vorschau anzeigen erfährst du, wie du Vorschauen aktivierst, akkumulierst und abgleichst.

In einem Workflow-Run führt der Server einen Workflow aus: ein Programm, das der Agent des primären Threads schreibt. Auf jedem Thread des Runs ist das erste agent.thread_message_received der Prompt, den der Workflow geschrieben hat. Seine from_session_thread_id ist die ID des primären Threads, und es hat keinen from_agent_name. Die API garantiert den Text des Prompts nicht, also parse ihn nicht. Das session.thread_status_terminated-Event des Threads im Stream des primären Threads teilt dir mit, dass der Thread fertig ist. Kein Event zeichnet das Ergebnis auf, das er an den Workflow zurückgegeben hat.

Der Stream eines Threads spielt frühere Events nicht erneut ab. Direkt nach session.thread_created kann die Event-Liste eines Run-Threads leer sein, weil der Server das erste Event des Threads danach schreibt. Öffne also zuerst den Stream des Threads, liste dann die Events des Threads auf und überspringe jedes gestreamte Event, dessen id die Liste zurückgegeben hat.

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

Tool-Berechtigungen und benutzerdefinierte Tools

Wenn ein Subagent etwas von deinem Client benötigt, etwa die Berechtigung, einen Tool-Aufruf auszuführen, oder das Ergebnis eines benutzerdefinierten Tools, wird das Event in den primären Thread gespiegelt, wobei session_thread_id den ursprünglichen Session-Thread identifiziert. Ein Tool-Aufruf benötigt deine Berechtigung unter always_ask oder unter auto, wenn der Server zu keiner Entscheidung gelangt.

{
  "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..."]
  }
}

Sende user.tool_confirmation (mit tool_use_id) oder user.custom_tool_result (mit custom_tool_use_id); der Server leitet die Antwort automatisch an den richtigen Thread weiter. Die Antwort kann auf dem primären Thread und auf dem Thread des Subagenten mit unterschiedlichen id-Werten erscheinen. Um die beiden Kopien einander zuzuordnen, vergleiche type und tool_use_id (bzw. custom_tool_use_id), nicht id.

Die Session wechselt erst zu idle, wenn kein Thread running ist, daher kann session.status_idle lange nach dem Aufruf eines Subagenten ankommen. Du musst nicht darauf warten: Sende das user.custom_tool_result, sobald das gespiegelte agent.custom_tool_use-Event ankommt.

Unter auto können deine user.message-Events den Server dazu bringen, einen Aufruf zu erlauben, den er sonst ablehnen würde. Nichts im Thread eines Subagenten zählt als deine Absicht. Dein Client sendet dort keine Nachrichten, und die Nachrichten, die der Agent des primären Threads an den Subagenten sendet, zählen nicht. Wenn der Server einen Aufruf unter auto ablehnt, wird nichts gespiegelt: Das Event und das Fehler-Tool-Ergebnis erscheinen nur im eigenen Thread-Stream des Subagenten, und der Subagent läuft weiter.

Das folgende Beispiel gehört in die Event-Schleife des Handlers für Tool-Bestätigungen. Für jede ID in stop_reason.event_ids sendet es eine user.tool_confirmation, die den Aufruf erlaubt. Dasselbe Muster gilt für user.custom_tool_result.

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

Das vorherige Muster beantwortet die Aufrufe, die ein Idle-Event auflistet. Im primären Stream kann das session.thread_status_idle-Event eines Subagenten vor den agent.tool_use- oder agent.mcp_tool_use-Events ankommen, die seine stop_reason.event_ids auflistet. Eine user.tool_confirmation für einen Aufruf, dessen Event noch nicht angekommen ist, kann 400 zurückgeben. Um das zu vermeiden, beantworte jeden Aufruf, dessen evaluated_permission ask ist, wenn sein eigenes Event im primären Stream ankommt.

Was this page helpful?