NeMo Guardrailsnemoguardrails 0.24.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
20 small wins to finish your path

RailOutcome: allow, block, transform

Lesson 18 used two of the three decisions a rail can return. This lesson looks at the object itself, at the third decision, and at the older style it replaced, which still appears in most material you will find online.

Three decisions

Example
from nemoguardrails.actions.rail_outcome import RailOutcome, TransformTarget

print(RailOutcome.allow().decision, RailOutcome.allow().is_blocked)
print(RailOutcome.block(reason="policy").decision, RailOutcome.block().is_blocked)
rewrite = RailOutcome.transform([(TransformTarget.BOT_MESSAGE, "redacted")])
print(rewrite.decision, rewrite.transforms[0].text)

allow lets the content through unchanged. block stops it, and the runtime decides how to present that; the outcome itself carries no refusal wording. transform replaces a conversation value, and the three it can replace are the user message, the bot message and the retrieved chunks.

reason and metadata are there for logs and for whatever reads them downstream. The documentation is explicit that metadata must not be load-bearing: code deciding what to do should read decision or is_blocked.

What it replaced

Example
from nemoguardrails.actions import action

try:
    @action(output_mapping=lambda value: not value)
    async def old_style():
        return True
except TypeError as error:
    print("TypeError:", error)

Older versions let an action return a boolean or a number and told the runtime how to read it with output_mapping. That argument is gone and passing it raises. The runtime no longer guesses a rail decision from a plain value at all.

An action reached through the library's own rail machinery must return a RailOutcome. An ordinary action whose result a flow reads itself, like check_length in lesson 16, may still return anything, because the if in the flow is doing the interpreting.

Which to use

Your action isReturn
Read by an if in your own flowWhatever is convenient: a bool, a string, a number
Standing in for a library railRailOutcome
Rewriting the message rather than refusing itRailOutcome.transform, or assign in the flow

Assigning in the flow is the simpler of the two rewrite routes and it is what lesson 22 uses.

Worth remembering
  • allow, block and transform are the three decisions.
  • is_blocked is the field a flow reads.
  • output_mapping is removed and raises TypeError.
Try it yourself
  • Call RailOutcome.transform([]) and read the error about transforms being non-empty.
  • Build a block outcome with metadata={"score": 0.91} and print it.

This is what real progress feels like.