Skip to main content

Policy Behavior

Flagged Review Configuration

flagged-review sends each response to a second model for review before your application gets it. The reviewer can allow, block, or escalate the response, or return an edited version. In escalate mode, the control skips the review model and escalates every response to a person.

The control reviews every response that reaches it, not only responses that another control flagged. Each review sends the input and output to the reviewer and can add a second model charge.

Syntax​

The reviewer must use a different provider name and endpoint host from the primary provider. With provider_isolation: true, changing only the model or the key is not enough. For example, the OpenAI reviewer below cannot review a primary request that went to api.openai.com.

Export VERDICTAN_OPENAI_REVIEW_KEY in the terminal that starts the gateway, and add these sections to a complete configuration:

Inside policy-config.yaml
policies:
  chain:
    - prompt-injection
    - flagged-review
    - audit-logger

policy:
  prompt-injection:
    embedding_threshold: 0.6
    response:
      action: block

  flagged-review:
    mode: judge
    provider:
      name: review-llm
      endpoint: https://api.openai.com/v1/chat/completions
      model: your-openai-review-model
      secret_key_ref:
        env: VERDICTAN_OPENAI_REVIEW_KEY
      timeout_ms: 5000
    recursion_depth_max: 1
    provider_isolation: true
    rationale_capture: true

Send requests with stream: false. A streaming request through a chain with flagged-review fails with streaming.policy_cannot_enforce.

Fields​

FieldTypeDefaultDescription
modestringjudgejudge, review_and_return, audit_only, or escalate
provider.namestringflagged-reviewProvider name stored in review records
provider.endpointstringhttps://api.openai.com/v1/chat/completionsOpenAI-compatible Chat Completions endpoint
provider.modelstringgpt-5.4-miniReview model
provider.secret_key_refobjectEnvironment variable with the review credential. env only.
provider.timeout_msinteger, 100 to 600005000Timeout of the review call
recursion_depth_maxinteger, 1 to 81Maximum review depth for one request
provider_isolationbooleantrueRejects a reviewer with the same provider name or endpoint host
rationale_capturebooleantrueStores the rationale of the reviewer
prompt_templatestringBuilt-inReview prompt with {input}, {output}, {reason_code}, and {mode}

In escalate mode, provider.name defaults to human_escalation and provider.model to manual_review. The runtime also reads provider.id, but lint accepts only provider.name.

Review modes​

ModeWhat happens
judgeThe reviewer's verdict applies to the response.
review_and_returnWith an allow or warn verdict, the gateway returns the reviewer's reviewed_response.
audit_onlyThe review is recorded. The verdict does not change.
escalateNo review call. Every response escalates.

Reviewer response​

In the three review modes, the review model must return one JSON object:

FieldRequiredDescription
verdictYesallow, warn, block, or escalate
review_summaryNoShort summary for operators. Falls back to rationale.
rationaleNoShort reason, stored when rationale_capture is true
reviewed_responseIn review_and_return with allow or warnThe revised response to return
Example reviewer response
{
  "verdict": "allow",
  "review_summary": "The answer follows the requested format.",
  "rationale": "No blocked content was found."
}

The gateway reads verdict, not decision. The reason code is flagged_review.<verdict>.

Examples​

Review and return with a custom prompt​

Inside policy-config.yaml
policy:
  flagged-review:
    mode: review_and_return
    provider:
      name: gpt4-reviewer
      model: your-openai-review-model
      secret_key_ref:
        env: VERDICTAN_OPENAI_REVIEW_KEY
      timeout_ms: 8000
    recursion_depth_max: 1
    provider_isolation: true
    rationale_capture: true
    prompt_template: |
      You are a safety reviewer.

      ## Input
      {input}

      ## Output
      {output}

      ## Reason
      {reason_code}

      Return ONLY valid JSON with these fields:
      Choose one verdict: allow, warn, block, or escalate.
      Example for an allowed revised answer:
      {"verdict":"allow","review_summary":"Checked the answer",
       "reviewed_response":"The revised answer", "rationale":"Reason"}

Escalate without a review call​

Inside policy-config.yaml
policy:
  flagged-review:
    mode: escalate
    recursion_depth_max: 1
    provider_isolation: true

Every response gets an escalation result with reason code flagged_review.escalate.

Verify one review​

  1. Apply the configuration to a test agent and send a short request with stream: false.
  2. Find flagged_review.allow, flagged_review.block, or flagged_review.escalate and the review summary in the runtime event.
  3. For review_and_return, check that the returned text is the reviewer's reviewed_response.
  4. For an escalation, open Inbox and check the assignment. Use escalation routing to send it to a specific team.

A successful HTTP response does not prove that a review ran. Look for the review record, also in audit_only mode.

Limits and failure behavior​

  • Every response that reaches the control is reviewed. An earlier block or escalate stops the chain before it.

  • These failures produce an escalation result. In audit_only mode, the result is only recorded and the answer still goes out. Use judge if a failed review must stop the answer.

    CaseReason code
    Review depth is above recursion_depth_maxflagged_review.recursion_depth_exceeded
    The reviewer has the same provider name or endpoint host as the primaryflagged_review.provider_isolation_failed
    The reviewer returns an invalid responseflagged_review.invalid_response
    The review call times out or failsflagged_review.timeout
  • In review_and_return, an allow or warn without reviewed_response counts as an invalid response.

  • Lint requires recursion_depth_max from 1 to 8. The runtime uses 1 for a lower value.

  • The control does not run on streaming responses.

Next steps​