메인 콘텐츠로 건너뛰기
키에 firewall 정책을 연결하면, 모델이 툴 호출을 스트리밍해 돌려보내고, response 스테이지가 에이전트가 그것에 따라 행동하기 전에 그것을 벗겨내거나 다시 씁니다. 강제 결정은 모든 프로바이더에서 동일합니다 — 같은 규칙, 같은 판정, 같은 이벤트. 다른 것은 firewall이 스트리밍된 툴 호출에 행동한 후 클라이언트가 보는 와이어 형태입니다. OpenAI chat, OpenAI Responses API, 그리고 네이티브 Claude /v1/messages가 각각 툴 호출을 다르게 프레이밍하기 때문입니다. 이 페이지는 그 고객 관측 가능한 차이에 대한 집중 노트입니다. 규칙 언어를 다시 문서화하지 않습니다 — Firewall rules 참조 — 스테이지 모델도 마찬가지입니다. Stages에서 다룹니다. 셋 모두가 공유하는 내부 보류-및-재조립 메커니즘은 스트리밍 내부를 읽으세요.

1. firewall 프로바이더 스트리밍이 와이어별로 다른 이유

비스트리밍 응답에서 firewall은 전체 응답을 한 번에 보고 결정합니다. 스트림에서, 모델의 툴 호출은 조각의 시퀀스로 도착합니다 — 한 프레임의 이름, 더 많은 프레임에 걸쳐 흘러나오는 인자 JSON. 판정은 완전한 호출(이름 전체 인자)을 필요로 하며, 툴 호출 조각은 일단 전달되면 철회할 수 없습니다. 그래서 모든 프로바이더에서 게이트웨이는 같은 일을 합니다: 일반 콘텐츠는 라이브로 스트리밍하게 두고, 호출이 완전히 조립될 때까지 툴 호출 프레임을 보류합니다. 스트림 끝에 각 조립된 호출을 평가하고 살아남은 것만 — 그 프로바이더 자체의 이벤트 형태로 — 발행합니다.
텍스트는 결코 멈추지 않습니다. 툴 호출 프레임만 보류됩니다. 어시스턴트 콘텐츠, 추론, 그리고 role 프레임은 라이브로 변경 없이 스트리밍됩니다. 보류는 첫 툴 호출 조각부터 그 턴의 끝까지 적용됩니다 — 그래서 채팅 전용 응답은 firewall이 연결되지 않은 것과 정확히 같이 스트리밍됩니다.

2. OpenAI chat completions

/v1/chat/completions에서, 툴 호출은 인덱스로 키가 지정된 delta.tool_calls 조각으로 스트리밍됩니다. 게이트는 그것들(과 레거시 delta.function_call 형태)을 보류하고, 닫는 프레임에서, 살아남은 호출을 0부터 재인덱싱하여 발행하고, 이어서 finish 프레임을 발행합니다:
결과클라이언트가 받는 것
allow원래 보류된 프레임을, 바이트 단위로 — 진정한 그대로 전달.
sanitize다시 쓰인 인자를 가진 tool_calls 델타 하나, 그 다음 finish_reason: "tool_calls".
deny (일부 호출)살아남은 호출만, 그 다음 finish_reason: "tool_calls".
deny (모든 호출)툴 호출 없음, 그 다음 finish_reason: "stop" — 턴은 모델이 텍스트로 답하기로 선택한 것처럼 보임.
그 마지막 행이 테스트할 신호입니다: firewall이 OpenAI chat 턴에서 모든 툴 호출을 벗겨내면, 에이전트는 오류 프레임이 아니라 깨끗한 finish_reason: "stop"을 봅니다. “이번 턴에 툴 호출 없음”을 유효한 결과로 다루도록 루프를 구축하세요.

3. OpenAI Responses API

네이티브 /v1/responses 스트림은 자체 이벤트 모델을 가집니다 — 툴 호출은 response.output_item.added로 열리고, response.function_call_arguments.delta 조각을 스트리밍하고, response.output_item.done에서 완료되는 function_call 항목입니다. firewall은 호출이 완전한 첫 지점인 done에서 평가합니다:
항목의 added / 인자 델타 / done 이벤트가 호출이 통과하면 변경 없이 발행됩니다.
added 셸이 스트리밍된 다음, 인자가 가려진 버전인 done — 원래 인자 델타 조각은 드롭되므로 가려지지 않은 값이 결코 도달하지 않습니다.
버퍼된 이벤트가 드롭되고, 거부된 항목은 클라이언트가 최종 상태를 구축하는 종착 response.completed 객체에서도 필터링됩니다 — 결코 실행되지 않은 호출에 대한 매달린 참조 없음.
텍스트와 추론 델타는 chat completions에서와 정확히 같이 내내 라이브로 스트리밍됩니다.

4. 네이티브 Claude /v1/messages

네이티브 Anthropic 스트림은 다른 짐승입니다: 콘텐츠가 인덱스된 블록으로 도착합니다 — content_block_startcontent_block_delta(input_json_delta 조각) → content_block_stopstop_reason을 담은 message_delta로 닫힙니다. firewall은 첫 tool_use 블록부터 보류하고, 각각을 평가하고, 연속 인덱스로 살아남은 블록을 재구성하므로 벗겨진 블록이 인덱스 갭을 남기지 않습니다. Claude 특유의 신호는 stop_reason입니다. 모든 tool_use 블록이 거부되면, tool_usestop_reason은 클라이언트에게 결코 도착하지 않는 툴 호출을 약속하게 됩니다 — 그래서 게이트웨이는 그것을 **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"}
부분 벗겨내기는 살아남은 tool_use 블록을 연속적으로 재인덱싱하여 유지하고, stop_reason: "tool_use"를 그대로 둡니다.
이것은 네이티브 Claude 스트림에 적용됩니다. OpenAI 형식 엔드포인트를 통해 호출된 Claude 모델은 대신 OpenAI chat 와이어에서 강제되므로(§2), stop_reason: "end_turn"이 아니라 finish_reason: "stop"을 보입니다. 종착 처리를 기저 모델이 아니라 호출한 와이어 형식에 맞추세요.

5. 하나의 구체적인 예

같은 규칙은 모든 프로바이더에서 같은 결정을 생성합니다 — 클라이언트가 읽는 와이어 형태만 다릅니다. response 스테이지에서 한 번 작성하세요:
{
  "stage": "response",
  "tool_name_glob": "shell.exec",
  "verdict": "deny",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf|mkfs\"}]}"
}
같은 프롬프트를 세 가지 방식으로 스트리밍하면 firewall은 매번 rm -rf 호출을 거부합니다. 클라이언트가 관측하는 것:
와이어전체 벗겨내기 후 종착 신호
OpenAI chatfinish_reason: "stop"
OpenAI Responsesresponse.completed에서 항목 부재
네이티브 Claudestop_reason: "end_turn"
매치되어 거부된 호출은 와이어와 무관하게 firewall 이벤트에 동일하게 나타나므로, 스트림은 아니어도 관측성은 프로바이더 무관합니다.

6. 프로바이더 전반에서 일정하게 유지되는 것

와이어는 다르지만; 계약은 다르지 않습니다:
  • 판정과 규칙은 와이어 무관입니다. allow / audit / deny / sanitize는 모든 프로바이더에서 같은 것을 의미합니다. Verdicts 참조.
  • Sanitize는 툴 호출 인자만 건드립니다, 툴이 반환하는 콘텐츠는 결코 아님 — 모든 와이어에서. 응답 정화 참조.
  • Allow은 진정한 그대로 전달입니다. firewall이 아무 행동도 하지 않을 때, 보류된 프레임은 정확한 업스트림 바이트로 재생됩니다 — 다시 배치 없음, 프로바이더 특정 필드 손실 없음.
  • Shadow mode는 어디서나 적용됩니다. 그것을 켜면 보류된 툴 호출은 항상 살아남으므로(audit로 강등), 정책이 트래픽을 변경하기 전에 프로바이더 전반의 영향을 측정할 수 있습니다. Shadow mode 참조.

7. 이것이 어디에 들어맞는가

스트리밍 내부

모든 프로바이더가 공유하는 보류-조립-재조립 메커니즘.

Stages

스트리밍된 툴 호출 강제가 왜 response 표면에 존재하는가.

Verdicts

스트리밍된 호출이 해석되는 프로바이더 무관 결정.

Response 필터링

스트림이든 아니든, 모델이 발행하는 툴 호출을 게이트.
이 스트리밍 검사가 다루는 위협은 위험한 툴 호출데이터 유출을 참조하세요; 스트림 강제가 요청 경로의 어디에 위치하는지는 강제 경로 지연을 참조하세요.