Skip to content

refactor(actions): resolve manifest actions lazily - #2186

Merged
Pouyanpi merged 14 commits into
developfrom
pouyanpi/rail-library-stack-5-lazy-actions
Jul 23, 2026
Merged

refactor(actions): resolve manifest actions lazily#2186
Pouyanpi merged 14 commits into
developfrom
pouyanpi/rail-library-stack-5-lazy-actions

Conversation

@Pouyanpi

@Pouyanpi Pouyanpi commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Description

Resolve manifest-declared action references only when an action is dispatched.
This keeps catalog and configuration discovery independent of action-module
imports and optional rail dependencies while preserving explicitly registered
actions and existing dispatcher behavior.

Directly importing action symbols from rail.py would make discovery execute
the runtime modules the manifest boundary is intended to isolate. structured
ActionRef values let the catalog index public action names first and resolve
their Python targets only when execution reaches that action. Decorator-based
registration remains supported for user and custom actions; manifest-backed
resolution is the built-in library path, not its replacement.

teach both action dispatch and the Colang runtime to load the owning manifest
action on demand, cache the resulting registration through the existing action
registry, and retain clear unknown-action and import-failure behavior. Add
dispatcher coverage for successful lazy resolution, explicit registrations,
unknown actions, and failed imports.

two focused test fixes patch the action-bound injection logger and jailbreak
NIM request rather than stale definition-module symbols. Lazy import timing made
those incorrect patch targets observable; production behavior is unchanged.

Path develop (eager walk) this branch (lazy)
Dispatcher construct / first config load ~812 ms, +117 modules, ~4.9 MB Python objects ~25 ms, +0 action modules
First dispatch of a given action already imported ~20 ms (that one action's module)
Repeat dispatch of the same action dict lookup dict lookup (~6 us)
Rail catalog discovery (default_rail_catalog) 29.7 ms / 33 rail.py 29.7 ms / 33 rail.py
LLMRails init with one rail enabled imports all ~34 library action modules imports 0 library action modules

Impact

  • Loading configuration or inspecting the rail catalog no longer imports every
    built-in action module or its optional runtime dependencies.
  • Applications pay an action's import cost only when that action is first
    dispatched, after which the existing registry caches it.
  • Explicitly registered custom actions retain precedence and behavior.
  • Unknown actions, invalid lazy targets, and import failures remain visible at
    the execution boundary with focused test coverage.
  • The observable timing of built-in action imports changes, but action results
    and dispatcher semantics remain unchanged.

Stack

Layer Branch Base PR
Stack 3 pouyanpi/rail-library-stack-3-manifest-contract develop #2157
Stack 4 pouyanpi/rail-library-stack-4-builtins Stack 3 #2181
Stack 4b pouyanpi/rail-library-stack-4b-flow-gate Stack 4 #2185
Stack 5 pouyanpi/rail-library-stack-5-lazy-actions Stack 4b #2186

Verification

AI Assistance

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

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me.
  • 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.

Summary by CodeRabbit

  • New Features

    • Added comprehensive GCP text moderation flows, including detailed violation-specific responses.
    • Added configurable blocking messages for retrieval safety and context-bloat detections.
    • Added a generated Rails configuration schema snapshot.
  • Bug Fixes

    • Corrected guardrail action references and flow syntax across Cleanlab, GCP moderation, and Fiddler integrations.
    • Improved lazy action loading and failure handling.
    • Updated regex and injection-detection behavior for more consistent blocking outcomes.
  • Tests

    • Added broad validation for rail configuration, flow portability, action declarations, and runtime equivalence.

@github-actions github-actions Bot added size: M status: needs triage New issues that have not yet been reviewed or categorized. labels Jul 17, 2026
@Pouyanpi Pouyanpi changed the title Pouyanpi/rail library stack 5 lazy actions refactor(actions): resolve manifest actions lazily Jul 17, 2026
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.23009% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
nemoguardrails/actions/action_dispatcher.py 98.05% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from b05380f to 33729cf Compare July 20, 2026 07:18
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from 6231c7a to 92f2417 Compare July 20, 2026 07:18
@github-actions github-actions Bot added size: XL and removed size: M labels Jul 20, 2026
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 33729cf to 26ce747 Compare July 20, 2026 12:34
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from 92f2417 to b373750 Compare July 20, 2026 12:34
@Pouyanpi Pouyanpi removed the status: needs triage New issues that have not yet been reviewed or categorized. label Jul 20, 2026
@Pouyanpi
Pouyanpi marked this pull request as ready for review July 20, 2026 13:54
@Pouyanpi Pouyanpi added the status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). label Jul 20, 2026
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR refactors the ActionDispatcher to load manifest-declared action references lazily — importing each action module only at the moment it is first dispatched rather than at startup. The co_v2 history filter is updated in tandem to use a dynamic is_rail_action event flag (set from is_manifest_action) instead of a hardcoded action-name exclusion list.

  • Introduces _RegisteredActions, a Mapping view that exposes lazy action names for membership/length checks without triggering module imports, and caches each imported action in _registered_actions after first resolution.
  • Adds _manifest_action_names set to track which actions originated from manifests throughout their lifecycle (including post-resolution), enabling the v2.x runtime to mark ActionFinished events with is_rail_action=True for the history filter.
  • Corrects two test patch targets (injection_detection logger name, jailbreak_nim_request import path) whose incorrect module strings were only observable because lazy import timing changed.

Confidence Score: 5/5

Safe to merge. The lazy resolution mechanism is well-encapsulated: exceptions are caught at both get_action and execute_action boundaries, _manifest_action_names correctly survives lazy resolution so is_manifest_action remains stable throughout a dispatch cycle, and the behavior change in filters.py is validated by the new AST-based manifest completeness test.

All changed code paths are covered by focused new tests. Error containment was the main risk identified in earlier review rounds and is now addressed. The _RegisteredActions Mapping asymmetry is documented and tested. No data-loss, incorrect-filtering, or import-side-effect regressions were found.

nemoguardrails/llm/filters.py — verify that every action name removed from the old hardcoded exclusion list is covered by a rail manifest declaration (the new AST test provides strong assurance but does not enumerate the specific removed names).

Important Files Changed

Filename Overview
nemoguardrails/actions/action_dispatcher.py Core change: adds lazy action registry (_lazy_action_refs, _manifest_action_names, _RegisteredActions view). Exception handling is correct at both get_action and execute_action; _manifest_action_names persists through resolution so is_manifest_action remains stable. Minor: values()/items() deliberately diverge from Mapping invariant (documented).
nemoguardrails/colang/v2_x/runtime/runtime.py Adds is_rail_action flag to the _run_action result dict and _get_action_finished_event; is_manifest_action checked before _process_start_action so it fires correctly for both unresolved and already-cached manifest actions.
nemoguardrails/colang/runtime.py Minor cleanup: action registration loop simplified, import_paths guard added, registered_actions return type updated to Mapping.
nemoguardrails/llm/filters.py Replaces hardcoded system_actions name list with is_rail_action flag; removed names (self_check_, llama_guard_, alignscore_*, jailbreak_detection_heuristics, CallActivefenceApiAction, CallGcpnlpApiAction) are now covered dynamically via manifest ownership.
tests/test_action_dispatcher.py Comprehensive new tests: lazy resolution and caching, override precedence, failure containment, log-injection escaping, and view semantics. Covers all new dispatcher code paths.
tests/rails/llm/test_builtin_rail_manifests.py Adds test_every_manifested_action_is_declared_in_its_manifest: AST-walks all manifested library packages and asserts every @action function is declared in some manifest's refs, preventing silent omissions.
tests/test_injection_detection.py Corrects caplog logger name from stale 'actions.py' to fully-qualified module name; fix was masked by eager loading before this PR.
tests/test_jailbreak_nim.py Corrects two @patch targets from request module to actions module for jailbreak_nim_request; valid fix now that lazy loading makes the wrong target observable.
tests/v2_x/test_run_actions.py Adds integration test confirming is_rail_action=True propagates from _run_action through _get_action_finished_event and is correctly filtered by co_v2.
tests/test_filters.py Replaces name-based vendor action exclusion test with is_rail_action flag test, and adds positive case for non-rail custom actions.

Sequence Diagram

sequenceDiagram
    participant Catalog as RailCatalog
    participant Dispatcher as ActionDispatcher
    participant LazyRefs as _lazy_action_refs
    participant ManifestNames as _manifest_action_names
    participant RegActions as _registered_actions
    participant Module as Action Module

    Note over Dispatcher: __init__(load_all_actions=True)
    Dispatcher->>Catalog: default_rail_catalog()
    Dispatcher->>LazyRefs: _register_manifest_action_refs()
    loop Each manifest ActionRef
        LazyRefs-->>ManifestNames: add(action_ref.name)
    end
    Note over Module: Module NOT imported yet

    Note over Dispatcher: First dispatch call
    Dispatcher->>Dispatcher: execute_action(action_name)
    Dispatcher->>Dispatcher: _normalize_action_name()
    Dispatcher->>LazyRefs: _has_action_name() → True
    Dispatcher->>Dispatcher: _resolve_registered_action()
    Dispatcher->>Module: resolve_import_ref(action_ref)
    Module-->>Dispatcher: resolved callable
    Dispatcher->>RegActions: cache resolved action
    Dispatcher->>LazyRefs: pop(action_name)
    Note over ManifestNames: name retained → is_manifest_action() still True

    Note over Dispatcher: Subsequent dispatch
    Dispatcher->>RegActions: get directly (no import)
    RegActions-->>Dispatcher: cached callable
Loading

Reviews (10): Last reviewed commit: "docs(actions): scope registered_actions ..." | Re-trigger Greptile

Comment thread nemoguardrails/actions/action_dispatcher.py
Comment thread nemoguardrails/actions/action_dispatcher.py
Comment thread nemoguardrails/actions/action_dispatcher.py Outdated
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 26ce747 to cb7c03c Compare July 20, 2026 15:49
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from b373750 to f959ca3 Compare July 20, 2026 15:49
@Pouyanpi
Pouyanpi marked this pull request as draft July 20, 2026 16:37
@Pouyanpi Pouyanpi self-assigned this Jul 21, 2026
@Pouyanpi Pouyanpi added this to the v0.24.0 milestone Jul 21, 2026
@Pouyanpi
Pouyanpi requested a review from tgasser-nv July 21, 2026 08:58
@Pouyanpi
Pouyanpi marked this pull request as ready for review July 21, 2026 08:59
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 6a88f13 to 1e2ca85 Compare July 21, 2026 09:43
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from f31d6a6 to 29e08df Compare July 21, 2026 09:43
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-4b-flow-gate branch from 1e2ca85 to 973f9f6 Compare July 22, 2026 07:13
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from 29e08df to 08d9c5c Compare July 22, 2026 07:13
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR standardizes built-in rail action identifiers, adds lazy action resolution through rail manifests, updates moderation and blocked-response flows, generates a Rails configuration schema snapshot, and adds conformance and runtime equivalence tests.

Changes

Rail runtime and flow conformance

Layer / File(s) Summary
Lazy action dispatch
nemoguardrails/actions/action_dispatcher.py, nemoguardrails/colang/runtime.py, tests/test_action_dispatcher.py
ActionDispatcher supports manifest-backed lazy references, unified action lookup, deferred resolution, and failure handling; Runtime uses the updated mapping interface and registration flow.
Portable action identifiers and flow calls
docs/configure-rails/..., nemoguardrails/library/{cleanlab,fiddler,regex,...}
Vendor action names and flow calls are standardized for portable Colang execution.
GCP moderation flow behavior
nemoguardrails/library/gcp_moderate_text/*
GCP moderation adds simple and detailed flows, violation-specific responses, asynchronous action calls, and updated abort behavior.
Configured blocked and transformed responses
nemoguardrails/library/{context_bloat_detection,gliner,injection_detection,polygraf,privateai,sensitive_data_detection}/*
Blocked retrieval responses use configured messages and BotMessage events; injection and regex flows update verdict and action handling.
Schema and library conformance checks
schemas/rails_config.snapshot.json, scripts/generate_rails_config_schema_snapshot.py, tests/rails/llm/*
A committed RailsConfigData schema snapshot and tests validate configuration, manifest declarations, portable surfaces, and library flow/action consistency.
Runtime equivalence coverage
tests/test_runtime_flow_gate_equivalence.py
Equivalence fixtures cover new retrieval, moderation, context-bloat, Polygraf, vendor naming, and injection-detection scenarios.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Runtime
  participant ActionDispatcher
  participant RailCatalog
  participant ActionTarget
  Runtime->>ActionDispatcher: initialize with rail_catalog
  ActionDispatcher->>RailCatalog: register manifest action refs
  Runtime->>ActionDispatcher: resolve action on use
  ActionDispatcher->>ActionTarget: import referenced callable
  ActionTarget-->>ActionDispatcher: return validated action
  ActionDispatcher-->>Runtime: execute cached action
Loading

Possibly related PRs

Suggested reviewers: tgasser-nv

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Results For Major Changes ⚠️ Warning Major refactor/test changes are present, but the PR description’s Verification section is blank and gives no test results or testing info. Add concrete verification details (e.g. tests run, results, and any manual checks) to the PR description, especially for the lazy action refactor.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: lazy resolution of manifest actions in the dispatcher/runtime.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pouyanpi/rail-library-stack-5-lazy-actions

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nemoguardrails/actions/action_dispatcher.py`:
- Around line 50-65: Update _RegisteredActions.__contains__ to check registered
action names through the dispatcher’s name registry, such as _action_names(),
without calling get_action or resolving imports. Ensure membership checks return
false for unknown names while preserving __getitem__ behavior for actual action
retrieval.

In `@schemas/rails_config.snapshot.json`:
- Around line 437-442: Update the owning action configuration field so its
advertised options match validation: either support sanitize in the field’s
pattern and implementation, or remove sanitize from the description. Then
regenerate schemas/rails_config.snapshot.json using the project’s
schema-generation tooling rather than editing the snapshot manually.

In `@tests/rails/llm/test_library_flow_files.py`:
- Around line 129-132: Update the declaration-only test’s action registration
loop to avoid calling resolve_import_ref(action_ref), keeping manifest actions
unresolved. Build or compare the dispatcher’s invoked names using the public
names indexed by each ActionRef, while preserving Python target resolution only
for execution-time paths.
- Around line 65-70: Validate the result from parse_colang_file before appending
it to parsed[version] in the file-parsing loop. Treat an empty result, including
the {} dialect-mismatch response, as a violation for the current manifest and
path, record an appropriate parse/mismatch message, and continue without
indexing it so later result["flows"] access cannot raise KeyError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a3f06c26-4661-4378-9ebb-4962b978f77c

📥 Commits

Reviewing files that changed from the base of the PR and between aa9caee and fe1b46c.

📒 Files selected for processing (33)
  • docs/configure-rails/guardrail-catalog/community/cleanlab.mdx
  • docs/configure-rails/guardrail-catalog/community/gcp-text-moderations.mdx
  • nemoguardrails/actions/action_dispatcher.py
  • nemoguardrails/colang/runtime.py
  • nemoguardrails/library/activefence/flows.v1.co
  • nemoguardrails/library/autoalign/flows.co
  • nemoguardrails/library/cleanlab/actions.py
  • nemoguardrails/library/cleanlab/flows.v1.co
  • nemoguardrails/library/cleanlab/rail.py
  • nemoguardrails/library/context_bloat_detection/flows.v1.co
  • nemoguardrails/library/fiddler/actions.py
  • nemoguardrails/library/fiddler/flows.v1.co
  • nemoguardrails/library/fiddler/rail.py
  • nemoguardrails/library/gcp_moderate_text/actions.py
  • nemoguardrails/library/gcp_moderate_text/flows.co
  • nemoguardrails/library/gcp_moderate_text/flows.v1.co
  • nemoguardrails/library/gcp_moderate_text/rail.py
  • nemoguardrails/library/gliner/flows.v1.co
  • nemoguardrails/library/injection_detection/flows.co
  • nemoguardrails/library/polygraf/flows.v1.co
  • nemoguardrails/library/privateai/flows.v1.co
  • nemoguardrails/library/regex/flows.co
  • nemoguardrails/library/sensitive_data_detection/flows.v1.co
  • nemoguardrails/llm/filters.py
  • schemas/rails_config.snapshot.json
  • scripts/generate_rails_config_schema_snapshot.py
  • tests/rails/llm/test_builtin_rail_conformance.py
  • tests/rails/llm/test_library_flow_files.py
  • tests/test_action_dispatcher.py
  • tests/test_filters.py
  • tests/test_injection_detection.py
  • tests/test_jailbreak_nim.py
  • tests/test_runtime_flow_gate_equivalence.py

Comment thread nemoguardrails/actions/action_dispatcher.py
Comment thread schemas/rails_config.snapshot.json Outdated
Comment thread tests/rails/llm/test_library_flow_files.py
Comment thread tests/rails/llm/test_library_flow_files.py Outdated
Pouyanpi added 5 commits July 22, 2026 15:35
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch from fe1b46c to 7e708b4 Compare July 22, 2026 13:39
Comment thread nemoguardrails/actions/action_dispatcher.py Fixed

@tgasser-nv tgasser-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, please take a look at the comments before merging

Comment thread tests/test_action_dispatcher.py
Comment thread nemoguardrails/colang/runtime.py Outdated
Comment thread nemoguardrails/actions/action_dispatcher.py Outdated
Pouyanpi added 5 commits July 23, 2026 10:22
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the pouyanpi/rail-library-stack-5-lazy-actions branch 2 times, most recently from 3c69e70 to 2df7b0a Compare July 23, 2026 08:48
Pouyanpi added 4 commits July 23, 2026 11:30
The registered_actions Mapping view resolved each name through get_action,
so materializing it (values, items, dict(view)) imported every lazily
declared action and raised KeyError on any whose optional dependency was
missing. Override values and items to expose only already-resolved actions
so bulk access never triggers lazy imports. Iteration, membership, and
subscription keep their existing semantics: names cover the full declared
namespace and subscripting still resolves a single action on demand.
Replace the full library tree walk and manifested-path skip set with a
direct load of LEGACY_UNMANIFESTED_LIBRARY_PACKAGES. Manifested library
actions are already indexed as lazy refs from the rail catalog, so the only
packages that still need eager loading are the two pre-manifest ones. This
drops the per-construction os.walk of the library and the re-import of every
manifest origin module used only to compute directories to skip. A test pins
the constant to the actual library layout so a new unmanifested action
package fails loudly instead of silently never registering.
The dispatcher registers manifested library actions solely from their
declared refs, so an `@action` in a manifested package that is missing from
every manifest's refs would silently never register. Add the reverse of the
existing ref-to-decorator check: scan each manifested library package for
`@action` functions and assert each one appears in some manifest's action
refs. The two legacy unmanifested packages are exempt.
Clarify that subscripting and dict(view) still resolve lazily (and can raise
KeyError), while only values() and items() are guaranteed not to trigger
imports. The prior wording implied any materialization was import-free.
@Pouyanpi
Pouyanpi merged commit 936cb9c into develop Jul 23, 2026
18 checks passed
@Pouyanpi
Pouyanpi deleted the pouyanpi/rail-library-stack-5-lazy-actions branch July 23, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants