Chat and guardrails
Chat choices
Section titled “Chat choices”client = shield.openai()response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}],)Use native clients when you need provider response or stream event objects, file or batch APIs, asynchronous clients, or provider-specific parameters.
response = shield.chat( model="openai/gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}], temperature=0.2,)With its default stream=False, shield.chat() posts to
/v1/chat/completions and returns a dictionary.
Stream unified chat
Section titled “Stream unified chat”Set stream=True to receive the exported synchronous ChatCompletionStream:
from deepintshield import ChatCompletionStream
stream: ChatCompletionStream = shield.chat( model="openai/gpt-4o-mini", messages=[{"role": "user", "content": "Explain the result"}], stream=True,)
with stream: for chunk in stream: print(chunk)The call opens the HTTP response and validates its initial status and required
SSE content type before it returns, but it does not buffer a successful response
body. Iteration yields one decoded dict[str, Any] for each
SSE data: event. SSE comments and events without data are ignored, multiple
data: lines in one event are joined with a newline, and the required terminal
data: [DONE] event is consumed without being yielded. An EOF before [DONE]
is treated as a truncated stream. The parser caps each successful SSE event at
1 MiB before JSON decoding. An oversized event closes the response and raises
chat_stream_invalid_event with details.reason == "event_too_large".
The stream is a single-consumer, closeable iterator and context manager. It
closes on [DONE], a truncated EOF, an event or transport failure,
explicit/context close, and early exit from a for loop. close() is
idempotent, and closed reports whether the response has been released. The
stream retains its owning client until it closes, so a temporary expression such
as DeepintShield(...).chat(stream=True) remains valid. Prefer with, or call
stream.close() when using next(stream) or when ownership crosses a function
boundary, so partial consumption releases the connection deterministically.
Initial HTTP and transport failures normally raise from chat() before an
iterator is returned. A non-success HTTP response retains at most 64 KiB of its
body for diagnostics. During iteration:
| Condition | Behavior |
|---|---|
Missing/wrong SSE content type, malformed UTF-8/JSON, oversized event, non-object payload, or EOF before [DONE] | DeepintShieldError with chat_stream_invalid_event |
| SSE error event or decoded object carrying an error | DeepintShieldError; a recognized gateway code is normalized, otherwise the fallback is chat_request_failed |
| Mid-stream HTTP/timeout failure | Native httpx exception with transport_error or transport_timeout metadata |
Owning DeepintShield client closed before the next read | DeepintShieldError with client_closed |
The stream itself is synchronous. Use a provider-native client when you need an asynchronous iterator or provider-specific event classes. See Error codes for structured handling.
Explicit guardrail evaluation
Section titled “Explicit guardrail evaluation”Use evaluate_guardrail() when you want a verdict object without automatic
exception behavior:
result = shield.evaluate_guardrail( stage="input", input="Please summarize this ticket", model="gpt-4o-mini", provider="openai", metadata={"ticket_id": "T-100"},)
print(result.decision, result.reason, result.mode)if result.blocked: # The application chooses what happens next. ...The SDK posts to POST /api/guardrails/evaluate and converts the response into
GuardrailResult:
| Attribute | Meaning |
|---|---|
decision | Lowercase gateway decision. |
stage | Stage supplied by the caller. |
reason | Gateway reason, possibly empty. |
mode | Reported enforcement mode such as sync, enforce, shadow, or async; possibly empty. |
raw | Complete decoded gateway response. Treat as sensitive. |
allowed | True only for allow, redact, or monitor. |
blocked | Logical inverse of allowed. |
The allowed property is decision-based; it does not reinterpret mode. When
operating policies in shadow/advisory mode, inspect both fields and validate the
behavior in a staging workspace.
Stages and fields
Section titled “Stages and fields”| Stage | Primary content fields | Typical helper |
|---|---|---|
input | input | shield.agent.check_input(text) |
output | output | shield.agent.check_output(text) |
action | tool_input, tool_name, action_class, domains | shield.agent.evaluate_tool(...) without a server |
mcp | action fields plus server_label | shield.agent.evaluate_tool(...) with a server |
rag | RAG-specific endpoint is preferred for retrieved chunks | shield.rag.evaluate(...) |
Other evaluation fields include actor type/id/role/customer/team, model,
provider, application and agent names, metadata, and persist. The gateway
currently normalizes an unrecognized stage to input; applications should
still treat the five values above as the supported contract and validate stage
names before calling.
Raise on a blocking decision
Section titled “Raise on a blocking decision”guard() evaluates and raises DeepintShieldBlockedError by default:
from deepintshield import DeepintShieldBlockedError
try: shield.guard(stage="output", output=answer)except DeepintShieldBlockedError as exc: print(exc.code, exc.stage, exc.decision, exc.reason)Set raise_on_block=False to always receive the result. The blocking exception
retains the structured stage, decision, reason, status/payload fields, and the
central guardrail_blocked error code. Do not display payload or raw policy
reasons directly to end users.
Agent-shaped explicit helpers
Section titled “Agent-shaped explicit helpers”shield.agent is a lightweight façade over the same guardrail endpoint:
from deepintshield import ToolInvocation
shield.agent.check_input(user_text)shield.agent.evaluate_tool( ToolInvocation( tool_name="write_invoice", tool_input={"invoice_id": "INV-7"}, action_class="write", domains=["billing"], ))shield.agent.check_output(model_text)@shield.agent.tool(...) performs this explicit pre-call check around one
synchronous function. For identity-aware PDP decisions, durable approvals,
registration, and automatic framework boundaries, use
the Agentic surface instead.
guard_turn() evaluates input, each listed tool call, and optional output in
that order and returns a dictionary keyed by stage/tool. It stops at the first
blocking exception unless raise_on_block=False.
Transparent gateway guardrails
Section titled “Transparent gateway guardrails”Requests made through a provider client can also be guarded transparently by
policies attached to the virtual key. Those failures normally surface through
the provider SDK’s HTTP exception type, not DeepintShieldBlockedError, because
the provider SDK owns response decoding. Use the response headers and structured
gateway body when the provider exception exposes them, then map the code through
the central error catalog.
Guardrail accuracy is policy- and detector-dependent. Test known-safe, known-bad, boundary, multilingual, and multimodal samples before enforcing a policy, and monitor false-positive/false-negative rates after deployment.