Saltar para o conteúdo principal
Você habilitou uma regra de superfície responsedeny ou sanitize nas chamadas de ferramenta que seu modelo emite — e seu agente chama o gateway com "stream": true. A pergunta que de fato importa: uma resposta em streaming pode vazar uma chamada de ferramenta bloqueada antes de o firewall decidir? Não pode, e esta página explica o único mecanismo que torna isso verdade para que você possa raciocinar sobre latência e os chunks que seu cliente recebe. Este é um olhar focado no comportamento SSE. Para os vereditos em si veja Vereditos; para a gramática de regras veja a referência de regras.

1. O problema do firewall sse em streaming

Uma resposta não-streaming é um corpo JSON — o firewall vê a coisa inteira, avalia os tool_calls, e retorna o resultado limpo. Um stream é diferente: um modelo emite uma chamada de ferramenta como dezenas de deltas de tool_call através de muitos frames SSE, e uma vez que um frame é encaminhado, seu agente já o tem — não há como retrair um token que você enviou. Avalie cedo demais e você não tem a chamada completa (nome + argumentos completos) para julgar; encaminhe conforme avança e um deny já é tarde demais. O gateway resolve isso com um contrato simples e observável:

Conteúdo faz streaming ao vivo

Deltas normais de texto e raciocínio passam inalterados, em tempo real — zero latência adicionada nos tokens que seu usuário lê.

Frames de chamada de ferramenta são retidos

Qualquer frame carregando um delta de tool_call (ou function_call legado) é retido do stream ao vivo até a chamada estar completa e avaliada.
O firewall é um portão de segurança, então ele parseia cada frame. Ele não adivinha que um frame é só-conteúdo a partir dos bytes crus — um membro tool_calls escapado em JSON não tem substring literal para corresponder, então um atalho de substring encaminharia uma chamada de ferramenta não avaliada. Os frames SSE são pequenos; o portão parseia cada um.

2. A sequência reter-montar-avaliar

Para uma resposta de chat-completions em streaming com uma política de superfície response ativa, cada frame que o upstream emite toma um de dois caminhos:
Faz streaming até seu cliente imediatamente, byte-a-byte. Esses nunca carregam uma chamada de ferramenta, então o firewall não tem nada a decidir.
Bufferizado fora do stream ao vivo. O frame de fechamento finish_reason de um turno de ferramenta é retido junto com ele, porque emiti-lo cedo diria ao seu cliente que o turno acabou antes de o firewall ter decidido.
No fim do stream, o gateway monta os frames retidos em chamadas de ferramenta completas (juntando os fragmentos de arguments transmitidos de cada chamada), avalia cada uma contra sua política na superfície responsea mesma semântica de veredito e regra que o caminho não-streaming — e emite apenas os sobreviventes:
Veredito da chamada retidaO que seu cliente recebe
allow / auditOs frames retidos originais, inalterados — uma passagem atrasada, não um chunk re-batcheado.
sanitizeA chamada com seus argumentos reescritos (segredos/PII correspondidos substituídos por um token tipado), re-emitida.
denyA chamada é descartada. Se era a única chamada do turno, o turno fecha com finish_reason: "stop" — o stream parece como se o modelo não tivesse feito nenhuma chamada de ferramenta.
Se nada correspondeu, você paga apenas o atraso de buffering nos frames de chamada de ferramenta — o conteúdo já fez streaming ao vivo. O firewall reconstrói frames apenas quando de fato age (um deny ou um sanitize); um allow limpo encaminha os bytes exatos do seu upstream.

3. Um exemplo concreto

Uma política de response com uma regra deny em *.delete (crie-a no editor de regras do console) e uma requisição em streaming cujo modelo decide chamar tanto db.query quanto db.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"}]}
Seu agente lê o texto do assistente em tempo real, depois recebe apenas db.querydb.delete foi montado, avaliado, negado e nunca emitido. A chamada sobrevivente é re-indexada a partir de 0, e o evento de firewall para a chamada negada aterrissa no seu log de events com a regra que disparou.
Faça o rollout de uma política de response em streaming primeiro sob shadow mode. No shadow mode cada veredito de enforcement é rebaixado para audit (motivo prefixado [shadow] would …) e todos os frames de chamada de ferramenta passam — então você pode confirmar que a política corresponde ao que você espera no tráfego em streaming real antes que ela comece a descartar chamadas.

4. Blocks inbound fazem curto-circuito antes de o stream começar

A dança de frames retidos é só para a superfície response — chamadas que o modelo emite. Um deny inbound (uma ferramenta que um agente anuncia) dispara antes da chamada ao modelo upstream, então uma requisição em streaming que aciona uma regra inbound nunca abre um stream SSE: ela retorna um HTTP 400 simples com o código de erro firewall_blocked, marcado como skip-retry. Sem frames, sem janela de retenção — o block aterrissa como qualquer erro não-streaming.

5. Guardrails no mesmo stream

Uma resposta em streaming pode carregar uma política de saída de Guardrail e uma política de response de firewall ao mesmo tempo. Elas agem sobre coisas diferentes — os guardrails filtram o texto que o modelo transmite; o firewall governa as chamadas de ferramenta — e elas se compõem:
  • Block de guardrail de saída (streaming): o scanner de saída corta o stream no momento em que uma regra dispara, encaminha um único chunk genérico de substituição — [Response blocked by content policy.] com finish_reason: "content_filter" — e para. A mensagem é deliberadamente genérica (sem categoria de regra) para que um sondador não possa enumerar sua política. Uma retenção de firewall em andamento quando isso acontece é descartada, então uma chamada de ferramenta retida não pode escapar depois do block.
  • Mask de guardrail de saída (streaming): o masking da requisição antes do modelo está ativo; o masking in-band ao vivo da saída em streaming está no roadmap. Num stream uma regra de mask registra a correspondência mas atualmente encaminha o chunk original — crie-a sabendo que a redação ainda não é reescrita na prática. O block de saída é totalmente aplicado em streams.
Esta página descreve a forma SSE de chat-completions da OpenAI. O mesmo contrato reter-avaliar-emitir é cabeado por formato — Anthropic Messages nativo, Gemini, xAI e o stream de OpenAI Responses cada um o carrega em sua própria forma de evento — então o comportamento observável pelo cliente é idêntico independentemente de qual provedor atendeu a requisição.

6. O que isso significa para o seu cliente

Algumas consequências práticas do modelo de frames retidos:
Um turno cuja única chamada de ferramenta foi negada fecha com finish_reason: "stop" em vez de "tool_calls" — para o seu agente lê-se como “o modelo escolheu não chamar uma ferramenta”. Um turno onde algumas chamadas sobreviveram fecha com "tool_calls", carregando apenas os sobreviventes.
Quando um upstream empacota o usage de token no mesmo chunk terminal que o firewall reteve, o gateway o re-anexa ao frame reconstruído final — um cliente que pediu usage de stream ainda o recebe.
Se o modelo emitiu conteúdo e uma chamada de ferramenta no mesmo frame, o conteúdo é recuperado e re-emitido mesmo quando a chamada de ferramenta é removida — bloquear uma chamada nunca descarta o texto do seu assistente.
Você não opta um stream para nada disso. Vincule uma política à chave (ou defina um padrão do workspace) e continue fazendo streaming exatamente como antes — o enforcement está no gateway.

Para onde ir a seguir

Stages e superfícies

inbound, response, mcp, egress — onde cada regra avalia.

Vereditos

allow, audit, deny, sanitize, pending_approval, cap_cost.

Sanitizar argumentos

Redija segredos dos argumentos de uma chamada de ferramenta — apenas na camada de argumento.

Shadow mode

Rebaixe vereditos de enforcement para audit enquanto você mede o impacto.
Para onde isso fica no caminho da requisição, veja como o OrcaRouter inspeciona e latência do caminho de enforcement. Para as ameaças que o enforcement de superfície response contém, veja chamadas de ferramenta perigosas e exfiltração de dados. Para a gramática de regras completa, veja a referência de regras do firewall.