何のためのものか
Agent SDK が回す実行ループの中身。CLI を動かしているのと同じループなので、ここが分かると CLI 側の挙動も同時に説明が付く。
触る
1 周は 5 段階。
- プロンプト受領 — システムプロンプト・ツール定義・会話履歴とともに Claude が受け取る →
SystemMessage(subtype"init") - 評価と応答 — テキスト、ツール呼び出し要求、またはその両方 →
AssistantMessage - ツール実行 — SDK が各ツールを実行し結果を集める。hook で実行前に介入・改変・拒否できる
- 反復 — 2 と 3 を繰り返す。1 周が 1 ターン
- 結果返却 — ツール呼び出しの無い応答が出たら終わり →
ResultMessage
まずは全メッセージをそのまま出力して、この並びを目で見る。
入れる
メッセージ型で分岐する。
| 型 | いつ出るか |
|---|---|
SystemMessage | セッションのライフサイクルイベント。subtype で区別する |
AssistantMessage | Claude の応答ごと |
UserMessage | ツール実行ごとに、Claude へ返すツール結果を伴って |
ResultMessage | ループの終了。最終テキスト・トークン使用量・コスト・セッション ID |
- 判定方法が言語で違う。 Python は import したクラスへの
isinstance()、TypeScript はtype文字列(message.type === "result") - TypeScript ではコンテンツブロックが
message.message.contentにある(message.contentではない) subtypeは"init"/"compact_boundary"/"informational"/"worker_shutting_down"。成功したか上限に当たったかはResultMessageのsubtypeで判定する
効かせる
- ターンはツール使用のぶんだけ数える。
max_turns/maxTurnsはツール使用のターンのみを数える。上限を設けなければ Claude が自分で終わるまで走る - 金額でも止められる。
max_budget_usd/maxBudgetUsd - 1 ターンの間、呼び出し側のコードに制御は戻らない。 途中で何かしたいなら hook を使う
SessionStart/Setuphook が走る場合、その hook ライフサイクルメッセージがinitより先に届く
落とし穴
ResultMessageでbreakしない。 その後にもprompt_suggestionなどの後続システムイベントが少数届きうる。ストリームは最後まで反復する- ループの駆動に必須でないイベントも流れてくる(レート制限の状態、タスク通知など)。知らない型で落ちない実装にする
- TypeScript では
"init"以外の subtype はSDKSystemMessageの subtype ではなく、SDKMessageunion の独立した型になる