feat(library): migrate built-in rail configuration to manifests#2181
feat(library): migrate built-in rail configuration to manifests#2181Pouyanpi wants to merge 9 commits into
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
6fbf0e2 to
d5532ad
Compare
ef8ce7e to
2310548
Compare
2f707ff to
4e1f759
Compare
4e1f759 to
49f9f7f
Compare
2310548 to
f72f3e2
Compare
Greptile SummaryThis PR migrates all built-in rail configurations from hard-coded fields in
|
| Filename | Overview |
|---|---|
| nemoguardrails/rails/llm/rails_config_fields.py | New discovery engine: projects manifest config specs into RailsConfigData fields; re-entrancy guard, idempotent re-registration, and export-collision detection all correctly implemented. |
| nemoguardrails/rails/llm/config.py | ~950 lines of hand-maintained rail config models removed; replaced by dynamic model construction via build_rails_config_data and module getattr for backward-compatible re-exports. Import-time collision validation added. |
| nemoguardrails/library/hf_classifier/rail_config.py | Discriminated union of LocalHFClassifierConfig / RemoteHFClassifierConfig migrated from config.py; validators correctly ordered; _KNOWN_PARAMS uses underscore prefix (Pydantic v2 private, not a field). |
| nemoguardrails/library/jailbreak_detection/rail_config.py | JailbreakDetectionConfig faithfully migrated with SecretStr api_key, deprecated field migration, and URL validation; two mode=after validators run in definition order (migrate then validate), which is the correct sequence. |
| nemoguardrails/library/regex/rail_config.py | RegexDetectionOptions with compile_patterns validator and _compiled_patterns PrivateAttr faithfully migrated; object.setattr bypass for frozen-like PrivateAttr mutation is correct Pydantic v2 pattern. |
| nemoguardrails/library/activefence/rail.py | Clean manifest for ActiveFence; threshold_mode bindings (simple/detailed) correctly declared for both input surfaces matching test assertions. |
| nemoguardrails/library/gcp_moderate_text/rail.py | ActionRef name 'call gcpnlp api' correctly matches @action(name='call gcpnlp api') in actions.py; threshold_mode bindings preserved for simple/detailed surfaces. |
| nemoguardrails/library/clavata/rail.py | ClavataCheckAction PascalCase name matches @action(name='ClavataCheckAction') in actions.py; surface bindings (text, rail) match flow file parameters. |
| nemoguardrails/library/autoalign/rail.py | Four action refs and surfaces for input/output/groundedness/factcheck correctly wired; groundedness action name matches test assertion for autoalign_groundedness_output_api. |
| nemoguardrails/library/polygraf/actions.py | Import of PolygrafDetection migrated from config.py to polygraf.rail_config; backward compatibility preserved via rail config export in getattr. |
| tests/rails/llm/test_builtin_rail_manifests.py | Comprehensive catalog tests: manifest completeness, action-name parity, binding-to-parameter matching, legacy flow contract preservation, env var documentation. |
| tests/rails/llm/test_config.py | New config tests verify clavata field defaults, null/yaml parsing, canonical config key set, and legacy export accessibility — thorough migration regression coverage. |
| pyproject.toml | Adds rail.py and rail_config.py glob patterns to the package include list, ensuring new manifest and schema files are shipped in the distribution. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant cfg as config.py (import time)
participant rcf as rails_config_fields.py
participant mfst as manifests registry
participant rcp as rail_config.py (per rail)
participant pyd as Pydantic create_model
cfg->>rcf: build_rails_config_data(base, module)
rcf->>rcf: discover_rails_config_fields()
rcf->>mfst: all_rail_manifests()
mfst-->>rcf: name to RailManifest for all built-in rails
loop each manifest with config_schema
rcf->>rcp: resolve_import_ref(ConfigSpecRef) then build_config_spec()
rcp-->>rcf: RailConfigSpec(annotation, field_info, exports)
rcf->>rcf: _add_config_field(fields, exports, RailsConfigField)
end
rcf->>pyd: create_model RailsConfigData with fields
pyd-->>cfg: RailsConfigData class baked into module
cfg->>rcf: validate_no_config_export_shadowing(globals())
cfg->>cfg: build __all__ from globals union config_exported_names
Note over cfg,pyd: Runtime attribute access
cfg->>rcf: __getattr__(name) calls resolve_config_export(name)
rcf-->>cfg: exported type e.g. ClavataRailConfig
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant cfg as config.py (import time)
participant rcf as rails_config_fields.py
participant mfst as manifests registry
participant rcp as rail_config.py (per rail)
participant pyd as Pydantic create_model
cfg->>rcf: build_rails_config_data(base, module)
rcf->>rcf: discover_rails_config_fields()
rcf->>mfst: all_rail_manifests()
mfst-->>rcf: name to RailManifest for all built-in rails
loop each manifest with config_schema
rcf->>rcp: resolve_import_ref(ConfigSpecRef) then build_config_spec()
rcp-->>rcf: RailConfigSpec(annotation, field_info, exports)
rcf->>rcf: _add_config_field(fields, exports, RailsConfigField)
end
rcf->>pyd: create_model RailsConfigData with fields
pyd-->>cfg: RailsConfigData class baked into module
cfg->>rcf: validate_no_config_export_shadowing(globals())
cfg->>cfg: build __all__ from globals union config_exported_names
Note over cfg,pyd: Runtime attribute access
cfg->>rcf: __getattr__(name) calls resolve_config_export(name)
rcf-->>cfg: exported type e.g. ClavataRailConfig
Reviews (7): Last reviewed commit: "fix(rails): parse configured flow model ..." | Re-trigger Greptile
abf6536 to
be38ebc
Compare
e5f87ad to
dc2be90
Compare
be38ebc to
938e50e
Compare
|
|
||
| flow clavata check input | ||
| """Check if the user input is benign.""" | ||
| $is_match = await ClavataCheckAction(text=$user_message, rail="input") | ||
|
|
||
| if $is_match.is_blocked | ||
| if $system.config.enable_rails_exceptions | ||
| send ClavataPolicyMatchException(message="Interaction blocked by clavata check on input.") | ||
| else | ||
| bot refuse to respond | ||
| abort | ||
|
|
||
| flow clavata check output | ||
| """Check if the bot output is benign.""" | ||
| $is_match = await ClavataCheckAction(text=$bot_message, rail="output") | ||
|
|
||
| if $is_match.is_blocked | ||
| if $system.config.enable_rails_exceptions | ||
| send ClavataPolicyMatchException(message="Interaction blocked by clavata check on output.") | ||
| else | ||
| bot refuse to respond | ||
| abort |
There was a problem hiding this comment.
this is to expose a consistent surface for both Colang dialects, check for colang 2.0 flow still works.
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>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Restore the exact pre-migration F5 and Polygraf schema descriptions, align AlignScore privacy metadata with its declared service, and stop advertising the flow-specific hallucination warning as a portable execution surface. Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Declare the missing Clavata input/output wrappers, context-bloat input/retrieval execution contracts, and jailbreak heuristic surface. Keep directionless Clavata dispatch and hallucination presentation flows out of the portable surface catalog. Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
dc2be90 to
372f999
Compare
938e50e to
4abf429
Compare
Description
Declare built-in library rails through the manifest contract and
project their typed configuration fields into
RailsConfig. Add manifests andconfiguration models for the built-in catalog, including F5, while preserving
the existing public configuration shape.
Each built-in rail keeps its cheap declaration in
rail.py. A separaterail_config.pyis needed only when that rail owns a typedrails.configcontribution; its schema factory remains behind a lazy reference until
RailsConfigconstruction needs it. This keeps core configuration genericwithout forcing catalog discovery to import Pydantic models or action modules.
Complete the execution metadata needed by non-Colang consumers: threshold-mode
bindings for ActiveFence and GCP, the correct AutoAlign groundedness action,
retrieval transform targets for the HF classifier and regex rails, and optional
self-check
$variantbindings. Add catalog-wide checks that action-bearinglibrary packages declare manifests and that bindings match callable contracts.
The large
config.pydeletion replaces hand-maintained per-rail fields withmanifest-driven projection; it is not removal of those configuration options.
Impact
RailsConfigkeys, defaults, and validation remain available whiletheir ownership moves into the corresponding rail packages.
field in core
rails.llm.config.available to downstream engines and tooling through one catalog.
rail_config.pymodules; shared schemas remain owned by their parent rail.their target callable before later execution layers consume them.
Audit
A structured audit compared every migrated built-in rail against the
pre-migration
config.py(defaults, types, validators, keys), checked eachmanifest binding against its real action signature, and verified the specific
claims above (ActiveFence/GCP threshold modes, AutoAlign groundedness action,
HF/regex retrieval transforms, self-check
$variant, config-less rails).Result: no default drift, no dropped validators or fields, no broken runtime
bindings.
Stack
pouyanpi/rail-library-stack-3-manifest-contractdeveloppouyanpi/rail-library-stack-4-builtinspouyanpi/rail-library-stack-4b-flow-gatepouyanpi/rail-library-stack-5-lazy-actionsRelated Issue(s)
AI Assistance
Checklist