Skip to content

feat(human_approval): add Colang v2 human-in-the-loop output approval rail#2132

Draft
MuneezaAzmat wants to merge 1 commit into
NVIDIA-NeMo:developfrom
MuneezaAzmat:feat/human-approval-rail
Draft

feat(human_approval): add Colang v2 human-in-the-loop output approval rail#2132
MuneezaAzmat wants to merge 1 commit into
NVIDIA-NeMo:developfrom
MuneezaAzmat:feat/human-approval-rail

Conversation

@MuneezaAzmat

Copy link
Copy Markdown
Contributor

Description

Adds a Colang v2 human-in-the-loop output approval library rail. When bot output matches configurable regex patterns, the flow pauses and asks a human reviewer to approve or reject before the original text is released.

What's included

  • Library module nemoguardrails/library/human_approval/:
    • HumanApprovalCheckAction — pattern matching against bot output
    • HumanApprovalMatchesKeywordsAction — keyword-based approve/reject parsing
    • Colang v2 flow: human approval on bot output $output_text
  • HumanApprovalConfig on RailsConfigData (patterns, approval_keywords, messages)
  • Example config: examples/configs/human_approval_v2/
  • Tests: 17 unit tests + 3 Colang v2 integration tests (approve, reject, multi-turn after reject)

Design notes

  • Implemented as a Colang v2 output rail (via import guardrails + custom flow output rails).
  • Patterns are pre-compiled at config load time with validation for invalid regex.
  • Rejection does not call abort; it sets $bot_message to the rejection message and completes normally so output rails keep firing on later turns (workaround for bug(v2): output rails silently stop firing after first abort in multi-turn conversations. #2067 until upstream fixes $output_rails_in_progress cleanup for other rails that still abort).
  • Multiline bot output (e.g. fenced SQL code blocks) is matched and released in full after approval.

Usage (Colang v2)

import guardrails
import nemoguardrails.library.human_approval

flow output rails $output_text
  await human approval on bot output $output_text
rails:
  config:
    human_approval:
      patterns:
        - "delete|drop|truncate"
        - "rm\\s+-rf"
      approval_keywords:
        - "approve"
        - "yes"

Related Issue(s)

Verification

  • poetry run pre-commit run --all-files — passed
  • poetry run pytest tests/test_human_approval.py tests/v2_x/test_human_approval.py tests/v2_x/test_human_approval_multiturn_2067.py -v — 20 passed
  • Manual smoke test with examples/configs/human_approval_v2/ + Ollama qwen2.5:14b (approve/reject/multi-turn)
  • Full make test — not run locally

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change (tool: Cursor).

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me. (feature: add human-in-the-loop approval rail for Colang v2 output rails #2121 filed; awaiting triage/assignment)
  • My PR title follows the project commit convention.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • I've noted any verification beyond CI and any checks I couldn't run.
  • I did not update generated changelog files manually.
  • I addressed all CodeRabbit, Greptile, and other review comments, or replied with why no change is needed.
  • @mentions of the person or team responsible for reviewing proposed changes.

Made with Cursor

… rail

Add a library rail that gates bot output behind configurable regex patterns
and an interactive approve/reject flow using Colang v2 output rails.

Rejection completes without abort so output rails keep firing on later turns
(workaround for NVIDIA-NeMo#2067). Includes HumanApprovalConfig,
example config, unit tests, and v2 integration tests.

Signed-off-by: Muneeza Azmat <muneezaazmat@utexas.edu>
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added size: L status: needs triage New issues that have not yet been reviewed or categorized. labels Jul 2, 2026
@rpelevin

rpelevin commented Jul 3, 2026

Copy link
Copy Markdown

This is a useful HITL output-rail shape. The one boundary I would make explicit before merge is that the approval should bind to the exact proposed bot output, not just to the reviewer keyword.

A concrete acceptance shape:

  1. When restricted output is detected, create an approval request with output digest, matched patterns, rail/config id, conversation/run id, turn id, and timestamp.
  2. The released text must match the approved output digest. If the model regenerates, edits, or another rail changes the output, require a fresh approval request.
  3. Reject should consume that request and emit a rejected terminal result, not leave an approval prompt reusable on a later output.
  4. Approval keywords should be scoped to a pending approval_request_id so an unrelated "approve" message cannot release the wrong output.
  5. Tests should cover changed-output-after-prompt, two simultaneous pending approvals if supported, and reject-then-new-turn re-prompting.

That keeps the rail focused: pattern matching decides when review is needed; the approval artifact decides exactly which output may be released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L status: needs triage New issues that have not yet been reviewed or categorized.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: add human-in-the-loop approval rail for Colang v2 output rails

2 participants