Output Controls
Bias Monitor
bias-monitor sends a narrow set of HR answers to a person for review: answers to hiring, promotion, or performance review questions that mention a protected attribute or an age. It matches fixed words. It is not a fairness classifier.
The score is either 0.0 or 0.95, not a probability of bias. Substring matching also causes false positives: "manager" contains "age".
Set up the review workflow first. A review decision does not replay the original request.
Configuration
Apply this to a test agent with the config-first workflow, and watch what it matches on real HR text before customers use it.
pack:
name: bias-monitor-example
version: 1.0.0
enabled: true
policies:
chain:
- bias-monitor
policy:
bias-monitor:
threshold: 0.85Verify the threshold
With threshold: 0.85, controlled provider responses give these results:
| Request mentions | Answer contains | Result |
|---|---|---|
performance review | gender | Escalated with bias.detected |
performance review | manager | Also escalated, a false positive of the age substring |
Summarize this recipe | No listed term or age phrase | Allowed with bias.clean |
An escalated caller receives no answer. Find the escalation in Inbox and read the nested bias result.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
threshold | number | 0.85 | The control acts when the score is at or above this value |
action | string | escalate | escalate or block. Needs gateway 0.1.26 or later. |
Lint rejects the removed field protected_characteristics. Gateway 0.1.25 and earlier also reject action and always escalate.
How it works
- The gateway lowercases the joined request messages and the response.
- A request that contains
hire,promotion, orperformance reviewis an HR request. - The control looks for
race,gender,religion,disability, oragein the response, and for age phrases such asover 40oryounger than 25. - An HR request with either kind of match scores
0.95. Everything else scores0.0. - A score at or above
thresholdescalates withbias.detected. Withaction: block, it blocks withbias.detectedand creates no escalation. Otherwise the answer is allowed withbias.clean.
The details contain action, score, threshold, is_hr_context, mentions_protected_characteristic, and has_age_reference.
Phase and verdicts
| Item | Value |
|---|---|
| Phase | output |
| Request families | Chat Completions, Completions, Responses, Messages |
| Verdicts | allow, escalate, block |
| Reason codes | bias.detected, bias.clean |
Limits and failure behavior
- Substring matching flags ordinary HR words, such as
manager. - Only the five terms and the age phrases count.
- Because the only non-zero score is
0.95, any threshold up to0.95escalates every HR match, and a higher threshold never escalates. - With gateway 0.1.26 or later,
bias-monitorexamines streamed Chat Completions, Responses, and Messages output. When the chain hasbias-monitor, the gateway holds all streamed output until the stream ends. If the score reaches the threshold, the stream stops with an escalation and the client gets no output text. Withaction: block, the stream stops with the error event "Streaming response blocked by policy: bias.detected" and the verdictBLOCK. Otherwise, the gateway sends all the output when the stream ends. A client that measures first-token latency sees the complete output at one time. See Output escalations in a stream. - An escalation returns HTTP
200withcontent: null,finish_reason: content_filter, and averdictanobject with verdictESCALATEand the escalation ID. The caller gets no model text. - A block of a buffered response returns the block error of the route, for example HTTP
400withcontent_policy_violationon Chat Completions. The decision has the verdictblockand no escalation. - A
whencondition does not limit this control. Use routes to apply it to some requests only.
Next steps
- Escalation Routing Configuration: route the escalations.
- Resolve an Escalation: claim and resolve them in the Inbox.