Register Behavior
Registration converts a valid component document into owned runtime behavior. The
example installs only the feature groups whose enabled values are true and reads
priority and break_chain directly from
configuration. It never calls a process-global middleware registrar from inside the
plugin.
An optional registration_control group in each complete example demonstrates an
activation-owned conditional middleware guardrail. It is disabled by default. When
enabled, the context qualifies the gate name and removes the gate automatically during
rollback or teardown. Refer to
Conditional Middleware Guardrails
before selecting and storing the target name.
Register an Activation-Owned Gate
The following examples register the same constant-result gate after configuration has supplied a discovered effective target name:
Python
Node.js
Rust
The component-local gate name does not need a plugin prefix. Relay qualifies the name and records its rollback operation. The target name is different: it must already be the effective name that discovery returned for the current runtime activation.
Register Event Metadata Injectors
An event metadata injector receives an event snapshot and returns flat metadata additions. Relay validates and inserts accepted additions before event sanitizers run. Existing metadata values are preserved.
The following examples register a component-owned callback through PluginContext:
Python
Node.js
Rust
Applications can instead use nemo_relay.event_metadata.register_injector() for a
global callback or nemo_relay.scope_local.register_event_metadata_injector() for a
callback owned by an active scope. The matching deregistration functions remove those
registrations.
Python and Node.js callbacks can return additions directly or asynchronously. Rust callbacks return a future. In every binding, callback failures and invalid return values omit that callback’s additions without dropping the event.
Register One Equivalent Request Intercept
The following excerpts show the same model-header rewrite. The full checked examples add event observation, tool policy, execution wrappers, and streaming verification around this common center.
Python
Node.js
Rust
The LLM intercept returns the
complete outcome rather than relying on
mutation. In particular, it preserves annotated. The Rust request is mutable inside its
owned callback value; Python creates a new typed request, and Node.js creates a new plain
object. Those language differences do not change Relay semantics.
Initialize and Inspect
Use the following procedure to verify successful activation and transactional rollback:
- Register the kind, validate the shared component, and stop if the report contains an error. Duplicate kind registration is itself an error and should fail the test.
- Initialize the valid document with Rust
initialize, Pythonnemo_relay.plugin.initialize, or Node.jsplugin.initialize. Keep the returned activation handle alive for the entire host lifetime. - Inspect the report on that handle. Rust uses
activation.report(), while Python and Node.js useactivation.report. It describes that activation without rerunning validation. - Execute an LLM request and inspect the real callback headers. Then emit an event and execute the representative tool and stream paths from the checked example.
- Force a later registration in the same component to fail. Initialization should reject, the new partial registrations should disappear, and Relay should restore the previous configuration when it can prove cleanup succeeded.
Success means configuration controls the installed surfaces, names are component-owned, the activation report matches the runtime effect, and failed registration leaves no half-active middleware.