Claude Platform Docs
Managed Agents高度なオーケストレーション

セッションスレッド

マルチエージェントセッションのスレッドを一覧表示、中断、アーカイブし、そのイベントを読み取り、スレッド全体でツール権限を処理します。

マルチエージェントセッションでは、各エージェントがそれぞれ独自の「session thread」(セッションスレッド)で作業します。このページでは、スレッドの一覧表示、中断、アーカイブの方法、スレッドが送信するイベント、およびスレッド全体でツール権限がどのように機能するかについて説明します。ワークフロー実行もセッションスレッドを作成します。

プライマリスレッドとセッションスレッド

「session-level event stream」(セッションレベルのイベントストリーム)(/v1/sessions/{session_id}/events/stream)は「primary thread」(プライマリスレッド)とみなされ、すべてのスレッドにわたるすべてのアクティビティの要約ビューを含みます。サブエージェントの完全なアクティビティは表示されませんが、その作業の開始と終了、およびツール権限リクエストなどのブロッキングイベントは表示されます。

セッションスレッドは、特定のエージェントのアクティビティを詳しく調べるための場所です。

セッションの status はすべてのエージェントアクティビティを集約したものです。少なくとも1つのスレッドが running であれば、セッション全体のステータスも running になります。実行中のワークフロー実行も、そのスレッドがいずれも作業していない間でさえ、セッションを running のままにすることがあります。作業中のスレッドがなく、あるスレッドがクライアントを待機している場合、セッションは idle になります。作業が完了したタイミングを知るを参照してください。

セッション予算は、セッションのすべてのスレッドで共有される単一の上限です。上限に達すると、スレッドはそれぞれ独立して一時停止し、各スレッドのコストはそのスレッド自身が使用したモデルの価格で計算されます。

スレッドを一覧表示する

セッションに関連付けられたすべてのスレッドを次のように一覧表示します。

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

完全なリストにはプライマリスレッドが含まれます。プライマリスレッドの parent_thread_id は null です。それ以外のすべてのスレッドは子スレッドです。workflow_run_id は、実行のスレッドを除いて null です。

特定のステータスを持つスレッドのみを一覧表示するには、リクエストに statuses[] を追加し、複数のステータスを指定する場合は ?statuses[]=running&statuses[]=idle のように繰り返します。省略すると、すべてのステータスのスレッドが返されます。

セッションスレッドを中断する

特定のスレッドを停止するには、session_thread_id を指定して user.interrupt を送信します。session_thread_id を省略すると、プライマリを含むセッション内のアーカイブされていないすべてのスレッドが中断されます。動的ワークフローを含むセッションでは、中断によって実行が終了することはなく、実行のスレッドを指定した中断は何も停止しません。中断は他の子スレッドの保留中のツール呼び出しを閉じますが、実行スレッドの保留中のツール呼び出しを閉じるためにこれに頼らないでください。実行が開いているセッションを中断するを参照してください。

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

requires_action でブロックされているサブエージェントのスレッドに対しては、中断により保留中の各ツール呼び出しがエラーのツール結果("Tool execution was interrupted before completion. Please retry.")で閉じられ、stop_reason: end_turn を伴う session.thread_status_idle が直接再送信されます。モデルはサンプリングされません。end_turn または budget_reached でアイドル状態の子スレッドに対しては、中断は何も行いません。終了したスレッドを指定した中断は400エラーを返します。中断された子スレッドは、ターン終了時に送信するレポートをプライマリスレッドのエージェントに送信しません。そのエージェントが子スレッドを待機している間は、user.message や別のスレッドのレポートなど、他の何かが届くまで次のターンを開始しません。

セッションスレッドをアーカイブする

必要に応じて、作業が完了したセッションスレッドをアーカイブします。スレッドをアーカイブすると、25個の子スレッド制限の枠が解放されます。ワークフロー実行のスレッドはサーバー自身がアーカイブします。それらをアーカイブする必要はなく、実行が開いている間はアーカイブできません。

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

アーカイブはスレッドが idle の場合にのみ成功します。requires_action で待機しているスレッドはアイドルとみなされ、直接アーカイブできます。実行中のスレッドのみ、先に中断する必要があります。

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)

プライマリスレッドのイベント

これらのイベントは、/v1/sessions/{session_id}/events/stream のプライマリスレッド上でマルチエージェントのアクティビティを表示します。メッセージの方向を示すイベントは、そのイベントが表示されるストリームのスレッドを基準に命名されています。agent.thread_message_received は別のスレッドからこのスレッドにメッセージが届いたことを意味し、agent.thread_message_sent はこのスレッドがメッセージを送信したことを意味します。たとえば、プライマリスレッドのエージェントが委任したタスクは、子スレッド自身のストリームに agent.thread_message_received イベントとして届きます。

タイプ説明
session.thread_createdスレッドが作成されました。session_thread_id と agent_name を含みます。
session.thread_status_runningスレッドがアクティビティを開始しました。
session.thread_status_idleスレッドに関連付けられたエージェントが入力を待機しています。エージェントが停止した理由を示す stop_reason を含みます。
session.thread_status_terminatedスレッドが終了し、それ以上の入力を受け付けません。たとえば、アーカイブされた場合や回復不能なエラーが発生した場合です。アドバイザースレッドも、その相談が終了すると終了します。
agent.thread_message_receivedプライマリスレッド上で、サブエージェントがプライマリスレッドのエージェントにレポートまたは質問を送信しました。from_session_thread_id、from_agent_name、content を含みます。
agent.thread_message_sentプライマリスレッド上で、プライマリスレッドのエージェントがサブエージェントにタスクまたはフォローアップメッセージを送信しました。to_session_thread_id、to_agent_name、content を含みます。

アドバイザーの相談は、予約名 anthropic.advisor の下でこれらと同じスレッドイベントを発行します(スレッドのライフサイクルイベントでは agent_name として、アドバイスの配信では from_agent_name として)。一連の流れについては、セッションにアドバイザーを与えるを参照してください。

ワークフロー実行のスレッドは、プライマリストリーム上で次のように表示されます。

  • ライフサイクルイベント: 各実行スレッドは、実行の workflow_run_id を伴う session.thread_created と、その session.thread_status_running、session.thread_status_idle、session.thread_status_terminated イベントを送信します。
  • メッセージイベント: 実行スレッドのプロンプト(agent.thread_message_received イベント)は、そのスレッド自身のストリームにとどまります。
  • 実行イベント: workflow_run.* イベントもこのストリームに届きます。実行イベントを参照してください。
  • クライアントを待機するツール呼び出し: クライアントを必要とする実行スレッドのツール呼び出しは、他の子スレッドと同様に、このストリームにクロスポストされます。ツール権限とカスタムツールを参照してください。

セッションスレッドのイベント

重要なイベントはプライマリスレッドにプロキシされます。ただし、特定のエージェントの推論やツール呼び出しを調査したい場合もあるでしょう。その場合は、関連するセッションスレッドからイベントをストリーミングまたは一覧表示します。

各セッションスレッドは /v1/sessions/{session_id}/threads/{thread_id}/stream に独自のイベントストリームを持ち、セッションレベルのストリームと同じ event_deltas[] パラメータを受け付けるため、モデルが生成するサブエージェントのテキストをプレビューできます。接続は読み取っているスレッドのみをプレビューします。子スレッドのプレビューはセッションレベルのストリームには表示されないため、サブエージェントをリアルタイムで監視するには、そのスレッド自身のストリームを開いてください。プレビューのオプトイン、蓄積、照合については、セッションスレッドのイベントをプレビューするを参照してください。

ワークフロー実行では、サーバーがワークフロー、つまりプライマリスレッドのエージェントが作成するプログラムを実行します。実行の各スレッドにおいて、最初の agent.thread_message_received はワークフローが作成したプロンプトです。その from_session_thread_id はプライマリスレッドのIDであり、from_agent_name はありません。APIはプロンプトのテキストを保証しないため、解析しないでください。プライマリスレッドのストリーム上のスレッドの session.thread_status_terminated イベントは、そのスレッドが完了したことを示します。スレッドがワークフローに返した結果を記録するイベントはありません。

スレッドのストリームは以前のイベントを再生しません。session.thread_created の直後は、サーバーがスレッドの最初のイベントをその後に書き込むため、実行のスレッドのイベントリストが空である場合があります。そのため、まずスレッドのストリームを開き、次にスレッドのイベントを一覧表示し、リストが返した id を持つストリーミングされたイベントはスキップしてください。

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

ツール権限とカスタムツール

ツール呼び出しを実行するための権限やカスタムツールの結果など、サブエージェントがクライアントから何かを必要とする場合、そのイベントは発生元のセッションスレッドを識別する session_thread_id とともにプライマリスレッドにクロスポストされます。ツール呼び出しは、always_ask の下、またはサーバーが判断に至らなかった場合の auto の下で、権限を必要とします。

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

user.tool_confirmation(tool_use_id を指定)または user.custom_tool_result(custom_tool_use_id を指定)を送信してください。サーバーは応答を正しいスレッドに自動的にルーティングします。応答は、プライマリスレッドとサブエージェントのスレッドに異なる id 値で表示される場合があります。2つのコピーを照合するには、id ではなく、type と tool_use_id(または custom_tool_use_id)を比較してください。

セッションは running のスレッドがない場合にのみ idle になるため、session.status_idle はサブエージェントの呼び出しからかなり後に届くことがあります。それを待つ必要はありません。クロスポストされた agent.custom_tool_use イベントが届いたらすぐに user.custom_tool_result を送信してください。

auto の下では、user.message イベントによって、サーバーが本来拒否する呼び出しを許可することがあります。サブエージェントのスレッド内のものは、あなたの意図としてはカウントされません。クライアントはそこにメッセージを送信せず、プライマリスレッドのエージェントがサブエージェントに送信するメッセージもカウントされません。サーバーが auto の下で呼び出しを拒否した場合、何もクロスポストされません。イベントとエラーのツール結果はサブエージェント自身のスレッドストリームにのみ表示され、サブエージェントは実行を続けます。

次の例は、ツール確認ハンドラーのイベントループ内に配置します。stop_reason.event_ids 内の各IDについて、呼び出しを許可する user.tool_confirmation を送信します。同じパターンが 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",
            }
        ],
    )

前述のパターンは、アイドルイベントが列挙する呼び出しに応答します。プライマリストリーム上では、サブエージェントの session.thread_status_idle イベントが、その stop_reason.event_ids が列挙する agent.tool_use または agent.mcp_tool_use イベントより先に届くことがあります。イベントがまだ届いていない呼び出しに対する user.tool_confirmation は400を返す場合があります。これを避けるには、evaluated_permission が ask である各呼び出しに、その呼び出し自身のイベントがプライマリストリームに届いた時点で応答してください。

Was this page helpful?