メインコンテンツへスキップ
response サーフェスルール — モデルが発行するツール 呼び出しに対する deny または sanitize — を有効にし、エージェントが "stream": true でゲートウェイを呼び出します。実際に重要な問い:ストリーミング レスポンスは、ファイアウォールが決定する前にブロックされたツール呼び出しを漏らせるか? できません。このページは、それを真にするひとつのメカニズムを説明するので、レイテンシと クライアントが受け取るチャンクについて推論できます。 これは SSE 挙動への焦点を絞った考察です。判定そのものについては 判定を;ルール文法については ルールリファレンスを参照してください。

1. ストリーミングファイアウォール sse の問題

非ストリーミングレスポンスは 1 つの JSON ボディです — ファイアウォールは全体を見て、 tool_calls を評価し、クリーニングされた結果を返します。ストリームは異なります: モデルはツール呼び出しを、多くの SSE フレームをまたいだ数十の tool_call デルタ として発行し、フレームが転送されると、エージェントはすでにそれを持っています — 送ったトークンを撤回する手段はありません。早すぎる評価では判断する完全な呼び出し (名前 + 完全な引数)がなく;進みながら転送すると deny はすでに手遅れです。 ゲートウェイはこれを、シンプルで観測可能なコントラクトで解決します:

コンテンツはライブでストリームされる

通常のテキストと推論デルタは変更なしで、リアルタイムに通過します — ユーザーが 読むトークンに追加レイテンシゼロ。

ツール呼び出しフレームは保持される

tool_call(またはレガシーの function_call)デルタを運ぶ任意のフレームは、 呼び出しが完了し評価されるまでライブストリームから差し控えられます
ファイアウォールはセキュリティゲートなので、すべてのフレームをパースします。 生の バイトからフレームがコンテンツのみだと推測しません — JSON エスケープされた tool_calls メンバーにはマッチするリテラル部分文字列がないため、部分文字列のショートカットは 評価されていないツール呼び出しを転送してしまうでしょう。SSE フレームは小さいです; ゲートは各フレームをパースします。

2. 保持・組み立て・評価のシーケンス

response サーフェスポリシーがアクティブなストリーミング chat-completions レスポンスでは、 アップストリームが発行する各フレームは 2 つのパスのうちの 1 つを取ります:
バイト単位で即座にクライアントにストリームされます。これらはツール呼び出しを決して 運ばないため、ファイアウォールに決定するものがありません。
ライブストリームからバッファされます。ツールターンの終了 finish_reason フレームも 一緒に保持されます。なぜなら、それを早く発行すると、ファイアウォールが判断する前に ターンが終わったとクライアントに伝えてしまうからです。
ストリーム終了時に、ゲートウェイは保持されたフレームを完全なツール呼び出しに 組み立て(各呼び出しのストリームされた arguments 断片を結合)、response サーフェスで ポリシーに対してそれぞれを評価し — 非ストリーミングパスと同じ判定とルールの セマンティクス — 生き残ったもののみを発行します:
保持された呼び出しの判定クライアントが受け取るもの
allow / audit元の保持されたフレーム、変更なし — 再バッチされたチャンクではなく、遅延した通過。
sanitize引数が書き換えられた(マッチしたシークレット/PII が型付きトークンで置き換えられた)呼び出し、再発行。
deny呼び出しはドロップされます。それがターンの唯一の呼び出しだった場合、ターンは finish_reason: "stop" で閉じます — ストリームはモデルがツール呼び出しをしなかったように見えます。
何もマッチしなければ、支払うのはツール呼び出しフレームのバッファリング遅延のみ です — コンテンツはすでにライブでストリームされました。ファイアウォールは実際に 作用するとき(deny またはサニタイズ)のみフレームを再構築します;クリーンな allow は アップストリームの正確なバイトを転送します。

3. 具体例 1 つ

*.delete 上の deny ルールを持つ response ポリシー(コンソールのルールエディタで それを作成)と、モデルが db.querydb.delete の両方を呼び出すことを決めた ストリーミングリクエスト:
SSE timeline (what your agent receives)
───────────────────────────────────────
data: {"choices":[{"delta":{"content":"Looking that up…"}}]}   ← live
data: {"choices":[{"delta":{"content":" one moment."}}]}        ← live
                                                                ← db.query + db.delete
                                                                  tool_call frames HELD
─── end of stream ───
data: {"choices":[{"delta":{"role":"assistant",
        "tool_calls":[{"index":0,"function":{"name":"db.query",…}}]}}]}
data: {"choices":[{"finish_reason":"tool_calls"}]}
エージェントはアシスタントテキストをリアルタイムで読み、それから db.query のみを 受け取ります — db.delete は組み立てられ、評価され、deny され、決して発行されません でした。生き残った呼び出しは 0 から再インデックスされ、deny された呼び出しの ファイアウォールイベントは、発火したルールとともに events ログに着地します。
ストリーミング response ポリシーはまずシャドウモードの もとでロールアウトします。シャドウモードでは、すべての強制判定が audit に格下げされ (理由に [shadow] would … が前置)、すべてのツール呼び出しフレームが通過します — そのため、呼び出しのドロップを開始する前に、実際にストリームされたトラフィックで ポリシーが期待どおりにマッチすることを確認できます。

4. inbound ブロックはストリームが始まる前にショートサーキットする

保持フレームのダンスは response サーフェス — モデルが発行する呼び出し — のみの ものです。inbound の deny(エージェントが アドバタイズするツール)はアップストリームのモデル呼び出しの前に発火するため、 inbound ルールをトリップするストリーミングリクエストは SSE ストリームをそもそも決して 開きません:それはエラーコード firewall_blocked のプレーンな HTTP 400 を返し、 skip-retry と マークされます。フレームなし、保持ウィンドウなし — ブロックは任意の非ストリーミング エラーのように着地します。

5. 同じストリーム上のガードレール

ストリーミングレスポンスは、ガードレール 出力ポリシーファイアウォール response ポリシーを一度に運べます。それらは異なる ものに作用します — ガードレールはモデルがストリームするテキストをスクリーニング します;ファイアウォールはツール呼び出しを統制します — そして合成されます:
  • 出力ガードレールブロック(ストリーミング): 出力スキャナはルールがトリップした 瞬間にストリームを切断し、単一の汎用置換チャンク — finish_reason: "content_filter" を持つ [Response blocked by content policy.] — を転送して停止します。メッセージは 意図的に汎用的です(ルールカテゴリなし)ので、探査者がポリシーを列挙できません。 これが起こったとき進行中のファイアウォール保持は破棄されるため、差し控えられた ツール呼び出しがブロック後に滑り出ることはできません。
  • 出力ガードレールマスク(ストリーミング): マスキングはモデルがライブになるに リクエストを;ストリームされた出力のライブインバンドマスキングはロードマップ上に あります。ストリームでは、マスクルールはマッチを記録しますが、現在は元のチャンクを 転送します — リダクションがまだワイヤー上で書き換えられていないことを知った上で 作成してください。出力ブロックはストリームで完全に強制されます。
このページは OpenAI chat-completions SSE の形を記述しています。 同じ 保持・評価・発行のコントラクトはフォーマットごとに配線されています — ネイティブの Anthropic Messages、Gemini、xAI、そして OpenAI Responses ストリームはそれぞれ独自の イベント形でそれを運びます — そのため、どのプロバイダがリクエストを処理したかに 関わらず、顧客が観測する挙動は同一です。

6. これがクライアントにとって何を意味するか

保持フレームモデルのいくつかの実用的な帰結:
唯一のツール呼び出しが deny されたターンは "tool_calls" の代わりに finish_reason: "stop" で閉じます — エージェントには「モデルはツールを呼ばないことを 選んだ」と読めます。一部の呼び出しが生き残ったターンは "tool_calls" で閉じ、 生き残ったもののみを運びます。
アップストリームがトークン usage をファイアウォールが保持した同じ終端チャンクに 束ねるとき、ゲートウェイはそれを最終の再構築されたフレームに再アタッチします — ストリーム usage を要求したクライアントは依然としてそれを受け取ります。
モデルがコンテンツツール呼び出しを同じフレームで発行した場合、ツール呼び出しが 剥がされてもコンテンツは回収され再発行されます — 1 つの呼び出しをブロックしても アシスタントテキストを決してドロップしません。
ストリームをこれのいずれにもオプトインしません。ポリシーをキーにアタッチし (またはワークスペースデフォルトを設定し)、以前と全く同様にストリームし続けます — 強制はゲートウェイにあります。

次に進む場所

ステージ & サーフェス

inbound、response、mcp、egress — 各ルールがどこで評価されるか。

判定

allow、audit、deny、sanitize、pending_approval、cap_cost。

引数のサニタイズ

ツール呼び出しの引数からシークレットをリダクト — 引数層のみ。

シャドウモード

影響を測定する間、強制判定を audit に格下げ。
これがリクエストパスのどこに位置するかについては、 OrcaRouter がどう検査するか強制パスのレイテンシを参照して ください。response サーフェスの強制が封じ込める脅威については、 危険なツール呼び出しデータ持ち出しを参照してください。完全な ルール文法については、ファイアウォールルールリファレンスを 参照してください。