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 anEvalResult with:
Standalone usage
Most integrations go throughRAILSession 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):
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.