response la rimuove o la riscrive
prima che il tuo agent agisca su di essa. La decisione di applicazione è identica
su ogni provider — stesse regole, stessi verdetti, stessi eventi. Ciò che differisce
è la forma del filo che il tuo client vede una volta che il firewall ha agito su
una chiamata a tool in stream, perché OpenAI chat, l’API OpenAI Responses e
/v1/messages nativo di Claude inquadrano ciascuno le chiamate a tool diversamente.
Questa pagina è la nota focalizzata su quelle differenze osservabili dal cliente.
Non ri-documenta il linguaggio delle regole — vedi
Regole del Firewall — o il modello degli stage,
trattato in Stage. Per il meccanismo interno di
trattieni-e-riassembla condiviso da tutti e tre, leggi
Internals dello streaming.
1. Perché lo streaming del firewall dei provider differisce per filo
Su una risposta non in stream il firewall vede l’intera risposta in una volta e decide. Su uno stream, la chiamata a tool del modello arriva come una sequenza di frammenti — un nome in un frame, JSON degli argomenti distillato attraverso molti altri. Un verdetto ha bisogno della chiamata completa (nome e argomenti completi), e un frammento di chiamata a tool, una volta inoltrato, non può essere ritrattato. Quindi su ogni provider il gateway fa la stessa cosa: lascia che il contenuto ordinario faccia stream live, e trattiene i frame delle chiamate a tool finché la chiamata non è completamente assemblata. Alla fine dello stream valuta ogni chiamata assemblata ed emette solo le sopravvissute — nella forma di evento di quel provider.Il tuo testo non si blocca mai. Solo i frame delle chiamate a tool vengono
trattenuti. I frame di contenuto, ragionamento e ruolo dell’assistant fanno stream
live e invariati. L’hold si applica dal primo frammento di chiamata a tool alla fine
di quel turno — così una risposta solo-chat fa stream esattamente come se nessun
firewall fosse collegato.
2. OpenAI chat completions
Su/v1/chat/completions, le chiamate a tool fanno stream come frammenti
delta.tool_calls indicizzati per indice. Il cancello trattiene quelli (e la forma
legacy delta.function_call) e, al frame di chiusura, emette le chiamate
sopravvissute ri-indicizzate da zero, seguite da un frame di finish:
| Esito | Cosa riceve il tuo client |
|---|---|
| allow | I frame trattenuti originali, byte per byte — gli stessi byte dell’upstream. |
| sanitize | Un delta tool_calls con argomenti riscritti, poi finish_reason: "tool_calls". |
| deny (alcune chiamate) | Solo le chiamate sopravvissute, poi finish_reason: "tool_calls". |
| deny (tutte le chiamate) | Nessuna chiamata a tool, poi finish_reason: "stop" — il turno appare come se il modello avesse scelto di rispondere in testo. |
3. API OpenAI Responses
Lo stream nativo/v1/responses ha il proprio modello di eventi — una chiamata a
tool è un item function_call che apre con response.output_item.added, fa stream
di frammenti response.function_call_arguments.delta e si completa a
response.output_item.done. Il firewall valuta a done, il primo punto in cui la
chiamata è completa:
allow → eventi bufferizzati emessi verbatim
allow → eventi bufferizzati emessi verbatim
Gli eventi
added / delta degli argomenti / done dell’item vengono emessi
invariati una volta che la chiamata passa.sanitize → shell dell'item + done riscritto
sanitize → shell dell'item + done riscritto
La shell
added fa stream, poi un done i cui argomenti sono la versione
redatta — i frammenti originali dei delta degli argomenti vengono scartati così
il valore non redatto non ti raggiunge mai.deny → item rimosso ovunque
deny → item rimosso ovunque
Gli eventi bufferizzati vengono scartati, e l’item negato viene anche filtrato
fuori dall’oggetto terminale
response.completed da cui il tuo client costruisce
il suo stato finale — nessun riferimento penzolante a una chiamata che non è mai
girata.4. Claude /v1/messages nativo
Uno stream Anthropic nativo è una bestia diversa: il contenuto arriva come blocchi
indicizzati — content_block_start → content_block_delta
(input_json_delta frammenti) → content_block_stop — chiusi da un
message_delta che porta stop_reason. Il firewall trattiene dal primo blocco
tool_use, valuta ciascuno, e ricostruisce i blocchi sopravvissuti con indici
contigui così un blocco rimosso non lascia alcun gap di indice.
Il segnale specifico di Claude è stop_reason. Se ogni blocco tool_use viene
negato, uno stop_reason di tool_use prometterebbe al tuo client una chiamata a
tool che non arriva mai — quindi il gateway lo riscrive in end_turn:
tool_use sopravvissuti, ri-indicizzati
in modo contiguo, e lascia stop_reason: "tool_use" intatto.
5. Un esempio concreto
La stessa regola produce la stessa decisione su ogni provider — differisce solo la forma del filo che il tuo client legge. Scrivila una volta, sullo stageresponse:
rm -rf
ogni volta. Cosa osserva il tuo client:
| Filo | Segnale terminale dopo una rimozione completa |
|---|---|
| OpenAI chat | finish_reason: "stop" |
| OpenAI Responses | item assente da response.completed |
| Claude nativo | stop_reason: "end_turn" |
6. Cosa resta costante tra i provider
Il filo differisce; il contratto no:- Verdetti e regole sono agnostici rispetto al filo.
allow/audit/deny/sanitizesignificano la stessa cosa su ogni provider. Vedi Verdetti. - Sanitize tocca solo gli argomenti della chiamata a tool, mai il contenuto che un tool restituisce — su ogni filo. Vedi Sanitizza le risposte.
- Allow consegna i byte esatti dell’upstream. Quando il firewall non compie alcuna azione, i frame trattenuti vengono riprodotti come i byte esatti dell’upstream — nessun ri-batching, nessun campo specifico del provider perso.
- La shadow mode si applica ovunque. Attivala e le chiamate a tool trattenute
sopravvivono sempre (declassate a
audit) così puoi misurare l’impatto di una policy tra i provider prima che modifichi il traffico. Vedi Shadow mode.
7. Dove si inserisce
Internals dello streaming
Il meccanismo trattieni-assembla-riassembla che ogni provider condivide.
Stage
Perché l’applicazione delle chiamate a tool in stream vive sulla superficie
response.Verdetti
Le decisioni agnostiche rispetto al provider in cui una chiamata in stream si risolve.
Filtraggio della response
Governare le chiamate a tool che un modello emette, in stream o no.
