Skip to main content
Concept: Policy Engine | Sessions: RAILSession | Middleware: RAILMiddleware
PolicyEngine decides what happens after a response is scored: pass it through, block it, attempt an automatic regeneration, or hand it to your own callback. You rarely construct it directly — RAILSession and RAILMiddleware both take a policy= argument and build a PolicyEngine for you. This page covers the shared Policy enum and, at the bottom, how to drive PolicyEngine standalone for advanced orchestration.

Policies

Policy is a string enum, so you can pass either the member or its value interchangeably (Policy.BLOCK and "block" are the same thing):

Via RAILMiddleware

The common case — score every response from your own generation function and enforce a policy on it:

Via RAILSession, with a custom callback

RAILSession forwards custom_callback into its PolicyEngine, so Policy.CUSTOM works here (unlike RAILMiddleware, which doesn’t currently expose a custom_callback parameter):

Handling a block

Policy.BLOCK raises RAILBlockedError rather than returning a result:

The result object

Whichever wrapper you use, a passing (or regenerated, log-only, or custom-handled) turn returns an EvalResult with:

Standalone usage

Most integrations go through RAILSession or RAILMiddleware. If you need to enforce a policy on evaluations you’re driving yourself — for example, Policy.DPDP_ENFORCE, which neither wrapper currently exposes — construct PolicyEngine directly. It expects the raw result dict from the API, which is what AsyncRAILClient.eval() returns (the sync RailScoreClient.eval() returns a parsed object instead, so use the async client here):
A DPDP violation configured with action: "block" raises DPDPBlockedError — see the DPDP page for the violation model and configuration shape.
Costs follow the underlying call — enforcing a policy doesn’t add a separate charge beyond the /eval (and, for Policy.REGENERATE, /safe-regenerate) requests it makes. See Credits for what each endpoint costs.