Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.egisai.co/llms.txt

Use this file to discover all available pages before exploring further.

When a policy decides to block a call, the SDK prevents the provider from ever being invoked. What your code sees afterwards depends on the on_block mode you set at initialization.

The two modes

on_block="raise"

A PermissionError is raised. Your existing exception handling catches it. Default.

on_block="stub"

A framework-shaped refusal object is returned. The shape matches what the provider would have returned, with content explaining that the call was refused by policy.
Set the mode at init:
egisai.init(..., on_block="raise")   # default
# or
egisai.init(..., on_block="stub")
Both modes record the same audit event on the dashboard. The difference is purely the in-process surface to your code.

When to choose raise

Use raise (the default) when:
  • You’d rather fail loudly than silently keep going.
  • Your application has a generic error path that can show a “request refused” message to a user.
  • You want a single, easy-to-grep signal in your logs.
import egisai
import openai

egisai.init(app="bot", on_block="raise")

client = openai.OpenAI()

try:
    response = client.chat.completions.create(
        model="gpt-4.1",
        messages=[{"role": "user", "content": user_input}],
    )
except PermissionError as exc:
    # `exc` includes the matched policy name and reason.
    return {"error": "Your request was refused.", "detail": str(exc)}

When to choose stub

Use stub when:
  • A single bad turn must not crash a long-running agent loop.
  • Your code already handles non-OK provider responses gracefully and treating blocks the same way is the cleanest path.
  • You want to surface a friendly refusal in the same shape your application already renders.
egisai.init(app="bot", on_block="stub")

client = openai.OpenAI()

response = client.chat.completions.create(
    model="gpt-4.1",
    messages=[{"role": "user", "content": user_input}],
)

text = response.choices[0].message.content
if response.choices[0].finish_reason == "policy_blocked":
    text = "I'm not able to help with that."
The exact shape of the stub matches what the provider would have returned for that method. For OpenAI Chat Completions you get a ChatCompletion-shaped object; for Anthropic Messages you get a Message-shaped object; and so on.

Identifying blocked calls in your logs

Both modes produce the same audit event with verdict="block". The matched rule name and reason code make it trivial to filter on the dashboard or in exported logs. In the local Python process:
  • raise — you’ll see a PermissionError traceback (unless caught).
  • stub — the returned object is shaped like a provider response. The audit event identifies it as a block.

Mixing modes

on_block is a per-process setting. If you need different behavior in different parts of your codebase, isolate them in separate processes (or call shutdown() and re-init when switching). For most applications, picking one mode and using your own application code to handle blocks consistently is simpler.

What’s next

Verdicts

The three outcomes the engine produces.

Troubleshooting

Diagnose unexpected blocks.