Approval
Tool call の手前に人を立て、自分の UI から決着させる。
モデルがそうすべきだと判断したからという理由で起きてはならない tool call があります — 返金する、メールを送る、レコードを削除する。そうしたものについては、run が一時停止して尋ねます。
Approval は session ログ上の 2 つの event の組なので、決める人がライブのストリームを見ていても、1 時間後に session を開いても、同じように動きます。
2 つの event
ゲートされた call が来ると、run は approval_requested を追記して待ちます。
| フィールド | 内容 |
|---|---|
call_id |
判断の対象となる call |
server |
その tool がどのサーバーのものか |
tool |
Tool 名 |
arguments |
モデルがそれを呼び出そうとしている引数 |
args_hash |
再発火の際に照合される同一性 |
arguments が要求 event に載っているのは意図的です。決める人は、対応する tool_call を探してログをさかのぼらなくても、自分が何を判断しているのかを見られます。
決着は approval_resolved として追記され、decision(allow または deny)、モデルに拒否理由を伝える任意の deny_message、そして resolved_by を持ちます。
UI を作る
要求を監視する
すでに session のストリームを追尾している client
は、他の event と同じように approval_requested
を受け取ります。その event 自身のフィールドから描画してください。
実際に何が尋ねられているかを示す
arguments はそのまま描画してください。approval
ゲートの価値は、要約ではなく本物の call を人が見ることにあります。
決着させる
要求が示した call_id に対して判断を投稿します。
POST /v1/sessions/{session_id}/approvals/{call_id}{ "decision": "deny", "message": "Refunds over $500 need a manager." }allow なら call が発火し、その tool_result が続きます。deny
なら、モデルは拒否を — 設定していればあなたのメッセージとともに —
受け取り、そこからターンが続きます。
message は deny だけのものです。{"decision": "allow"} と一緒に送ると、無視されるのではなく拒絶されます。allow がモデルの見ない誘導文をひそかに運ぶことはありません。
判断は速やかに。call を保持している broker は次のティックであなたの判断を読み、engine にそのまま答えます。その保持時間を過ぎると run は再キューされて call を発火し直します — args_hash はそれを照合するために存在します。
拒否は失敗ではない
拒否された call は正常な結果であって、エラーではありません。モデルはそう告げる tool 結果を受け取って先へ進みます。だからこそ deny_message を書く価値があります。「承認されませんでした」ではモデルは推測するしかありませんが、「$500 を超える返金にはマネージャーの承認が必要です」なら次に何をすべきかが伝わります。