Saltar para o conteúdo principal
Você vincula uma política de firewall a uma chave, o modelo transmite uma chamada de ferramenta de volta, e o stage response a remove ou reescreve antes que seu agente aja sobre ela. A decisão de enforcement é idêntica em cada provedor — mesmas regras, mesmos vereditos, mesmos events. O que difere é a forma na transmissão que seu cliente vê uma vez que o firewall agiu sobre uma chamada de ferramenta em streaming, porque OpenAI chat, a OpenAI Responses API e o Claude /v1/messages nativo cada um enquadra as chamadas de ferramenta de forma diferente. Esta página é a nota focada nessas diferenças observáveis pelo cliente. Ela não re-documenta a linguagem de regras — veja Regras do Firewall — ou o modelo de stage, coberto em Stages. Para o mecanismo interno de reter-e-remontar compartilhado pelos três, leia Internals de streaming.

1. Por que o streaming de provedor do firewall difere por transmissão

Numa resposta não transmitida o firewall vê a resposta inteira de uma vez e decide. Num stream, a chamada de ferramenta do modelo chega como uma sequência de fragmentos — um nome num frame, o JSON de argumento pingando através de muitos mais. Um veredito precisa da chamada completa (nome e argumentos completos), e um fragmento de chamada de ferramenta, uma vez encaminhado, não pode ser retraído. Então em cada provedor o gateway faz a mesma coisa: ele deixa o conteúdo comum fazer streaming ao vivo, e retém os frames de chamada de ferramenta até a chamada estar totalmente montada. Ao fim do stream ele avalia cada chamada montada e emite apenas os sobreviventes — na própria forma de evento daquele provedor.
Seu texto nunca trava. Apenas os frames de chamada de ferramenta são retidos. Frames de conteúdo, raciocínio e role do assistente fazem streaming ao vivo e inalterados. A retenção se aplica do primeiro fragmento de chamada de ferramenta até o fim daquele turno — então uma resposta só-de-chat faz streaming exatamente como se nenhum firewall estivesse vinculado.

2. OpenAI chat completions

Em /v1/chat/completions, chamadas de ferramenta fazem streaming como fragmentos delta.tool_calls chaveados por índice. O portão retém esses (e a forma legada delta.function_call) e, no frame de fechamento, emite as chamadas sobreviventes re-indexadas a partir de zero, seguidas por um frame de finalização:
ResultadoO que seu cliente recebe
allowOs frames retidos originais, byte-a-byte — passagem verdadeira.
sanitizeUm delta tool_calls com argumentos reescritos, depois finish_reason: "tool_calls".
deny (algumas chamadas)Apenas as chamadas sobreviventes, depois finish_reason: "tool_calls".
deny (todas as chamadas)Nenhuma chamada de ferramenta, depois finish_reason: "stop" — o turno parece como se o modelo tivesse escolhido responder em texto.
Essa última linha é o sinal contra o qual testar: quando um firewall remove cada chamada de ferramenta de um turno de OpenAI chat, seu agente vê um finish_reason: "stop" limpo, não um frame de erro. Construa seu loop para tratar “nenhuma chamada de ferramenta neste turno” como um resultado válido.

3. OpenAI Responses API

O stream nativo /v1/responses tem seu próprio modelo de evento — uma chamada de ferramenta é um item function_call que abre com response.output_item.added, transmite fragmentos response.function_call_arguments.delta, e completa em response.output_item.done. O firewall avalia em done, o primeiro ponto em que a chamada está inteira:
Os eventos added / argument-delta / done do item são emitidos inalterados uma vez que a chamada passa.
O shell added faz streaming, depois um done cujos argumentos são a versão redigida — os fragmentos de argument-delta originais são descartados para que o valor não redigido nunca chegue a você.
Os eventos bufferizados são descartados, e o item negado também é filtrado do objeto terminal response.completed a partir do qual seu cliente constrói seu estado final — nenhuma referência pendente a uma chamada que nunca rodou.
Deltas de texto e raciocínio fazem streaming ao vivo o tempo todo, exatamente como em chat completions.

4. Claude /v1/messages nativo

Um stream Anthropic nativo é um bicho diferente: o conteúdo chega como blocos indexadoscontent_block_startcontent_block_delta (input_json_delta fragmentos) → content_block_stop — fechado por um message_delta carregando stop_reason. O firewall retém a partir do primeiro bloco tool_use, avalia cada um, e reconstrói os blocos sobreviventes com índices contíguos para que um bloco removido não deixe gap de índice. O sinal específico do Claude é stop_reason. Se cada bloco tool_use é negado, um stop_reason de tool_use prometeria ao seu cliente uma chamada de ferramenta que nunca chega — então o gateway o reescreve para end_turn:
upstream:  content_block_start (tool_use) … message_delta {stop_reason: "tool_use"}
            ↓ firewall denies the only tool_use
client:    (no tool_use block)            … message_delta {stop_reason: "end_turn"}
Uma remoção parcial mantém os blocos tool_use sobreviventes, re-indexados contiguamente, e deixa stop_reason: "tool_use" intacto.
Isto se aplica a streams Claude nativos. Um modelo Claude chamado através de endpoints em formato OpenAI é aplicado na transmissão de OpenAI chat em vez disso (§2), então ele mostra finish_reason: "stop", não stop_reason: "end_turn". Combine seu tratamento de fim-de-turno com o formato de transmissão que você chamou, não com o modelo subjacente.

5. Um exemplo concreto

A mesma regra produz a mesma decisão em cada provedor — apenas a forma na transmissão que seu cliente lê difere. Crie-a uma vez, no stage response:
{
  "stage": "response",
  "tool_name_glob": "shell.exec",
  "verdict": "deny",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf|mkfs\"}]}"
}
Transmita o mesmo prompt de três maneiras e o firewall nega a chamada rm -rf toda vez. O que seu cliente observa:
TransmissãoSinal terminal após uma remoção completa
OpenAI chatfinish_reason: "stop"
OpenAI Responsesitem ausente de response.completed
Claude nativostop_reason: "end_turn"
A chamada correspondida-e-negada aparece identicamente em events de firewall independentemente da transmissão, então sua observabilidade é agnóstica a provedor mesmo que o stream não seja.

6. O que permanece constante através dos provedores

A transmissão difere; o contrato não:
  • Vereditos e regras são agnósticos à transmissão. allow / audit / deny / sanitize significam a mesma coisa em cada provedor. Veja Vereditos.
  • O sanitize toca apenas nos argumentos da chamada de ferramenta, nunca no conteúdo que uma ferramenta retorna — em cada transmissão. Veja Sanitizar respostas.
  • Allow é passagem verdadeira. Quando o firewall não toma nenhuma ação, os frames retidos são reproduzidos como os bytes upstream exatos — sem re-batching, sem campos específicos de provedor perdidos.
  • O shadow mode se aplica em todo lugar. Ligue-o e as chamadas de ferramenta retidas sempre sobrevivem (rebaixadas para audit) para que você possa medir o impacto de uma política através dos provedores antes que ela mude o tráfego. Veja Shadow mode.

7. Onde isso se encaixa

Internals de streaming

O mecanismo de reter-montar-remontar que cada provedor compartilha.

Stages

Por que o enforcement de chamada de ferramenta em streaming vive na superfície response.

Vereditos

As decisões agnósticas a provedor para as quais uma chamada em streaming resolve.

Filtragem de response

Controlando as chamadas de ferramenta que um modelo emite, em stream ou não.
Para as ameaças que essas verificações em streaming endereçam, veja Chamadas de ferramenta perigosas e Exfiltração de dados; para onde o enforcement de stream fica no caminho da requisição, veja Latência do caminho de enforcement.