2つの agent 間のハンドシェイクプロトコル
Agent 同士も「合意書」を交わす。request_id が合意書の番号だ。
なぜプロトコルが必要なのか
s09 では send_message で何でも送れた。しかし2つの agent が何かについて合意する必要があるとき(例:「シャットダウンしていいか?」)、ただ文字列を送るだけでは不十分だ——必要なのは:
- リクエストに明確な識別子(request_id)——レスポンスがどのリクエストに対応するか特定するため。
- ステートマシン:pending → approved | rejected、各状態の結果が明確。
- 一貫したフィールド:両者が
approve: trueの意味を理解している。
これが shutdown_request / shutdown_response / plan_approval / plan_approval_response が存在する理由だ。
Shutdown プロトコルの全体フロー
lead が alice に仕事を終わらせたい:
lead: # shutdown_request を送信、サーバー側で request_id を記録 req_id = uuid4()[:8] shutdown_requests[req_id] = {"target": "alice", "status": "pending"} send("alice", "shutdown_request", extra={"request_id": req_id}) alice: # 次のループで inbox を読み、shutdown_request を確認 # 決断:手元の作業を終えてから応答、approve する tool_use("shutdown_response", request_id=req_id, approve=True) lead: # shutdown_response を受信し、トラッカーを approved に更新 shutdown_requests[req_id]["status"] = "approved" # alice スレッドはシャットダウンを受理したことを検出し、status=shutdown でループを抜ける
Shutdown FSM の可視化
ステートマシンを一歩ずつ進めよう。alice は reject することもできる——「重要な作業中なので今は止まれない」という意味だ。
Plan Approval · 同じパターン、異なるドメイン
teammate が大きな操作を始める前に plan を提出して lead の承認を求める:
alice: tool_use("plan_approval", plan="auth モジュール全体を JWT で書き直すつもりです") # alice は lead を待ちながら idle を続ける lead: # alice の plan_approval_response リクエストを確認 tool_use("plan_approval", request_id="...", approve=False, feedback="auth には手を付けないで。来月全体的なリファクタリングをする予定だから")
s10 のソースコードを見ると:2つのプロトコルは全く同じ request_id トラッキングパターンを使っている——ディクショナリの名前が違うだけだ(shutdown_requests vs plan_requests)。これが「一つのパターン、二つのドメイン」だ。
なぜ汎用 Protocol 基底クラスに抽象化しないのか?s10 はあえて抽象化しない。理由:今のところプロトコルは2つしかなく、抽象化のメリットがまだ明確ではない。各プロトコルを独立して理解できる形で書いた方がわかりやすい。4つ目・5つ目が増えたら抽出すればいい(rule of three)。