Observe and Sanitize
The example’s observe feature group installs an Event metadata injector, subscriber, mark sanitizer,
scope-start sanitizer, scope-end sanitizer, tool request and response sanitizers, and LLM
request and response sanitizers. The group is enabled independently and receives the
configured tag and redact_keys, so operators can see exactly which behavior one
setting controls.
Register the Observation Surfaces
The function returns immediately when observation is disabled, so a report for that configuration cannot claim registrations that do not exist. One helper implements the shared event-field transformation, but each event surface is registered separately.
The local name is unique only within this component. The closure clones owned strings
and arrays into each async callback; it never borrows the component configuration after
register returns.
Inject Event Metadata
Register a component-owned callback to propose metadata for every Event while the plugin is active. The callback receives an immutable Event snapshot and returns flat key/value additions:
Relay validates and merges accepted additions before Event sanitizers run. A callback error omits that callback’s additions without dropping the Event. Clearing the plugin component removes the registration.
Keep Real Values Separate from Event Values
A sanitizer returns the fields Relay should publish. It never changes the request that
the real callback receives or the response that the application receives. To prove that
distinction, place a configured secret field in a managed tool request, observe the
redacted start event, and confirm that the tool callback still receives the original
value.
Event sanitizers receive an immutable event together with mutable copies of data,
category_profile, and metadata. The example walks those JSON values recursively,
replaces keys listed by observe.redact_keys, and adds the documentation tag to the
returned metadata. It registers all three event-specific callbacks because mark,
scope-start, and scope-end are separate public surfaces.
The subscriber observes the sanitized event stream and emits no recursive event for an event already created by the example. Because native subscribers are synchronous, it does only bounded local work. Network export or other asynchronous I/O belongs in typed middleware or a purpose-built exporter with its own queue and shutdown behavior.
Use Codecs for Model Payloads
LLM sanitizers receive a request or response plus a structured context. For requests, the example resolves the directional codec when one is available, redacts the normalized annotation, and encodes it back onto the original envelope before applying its raw JSON fallback. Response codecs expose decode but not a symmetric response encoder, so the response sanitizer resolves and decodes the active codec for normalized inspection, then returns a redacted provider envelope. When the codec is absent or opaque, both callbacks redact the original JSON safely. Returning no payload omits that request or response from observability; it does not block the model call.
The codec facade is valid only for the callback lifetime. It can remain in the typed
future across an await, because the SDK owns that lifetime, but it must not be cached in
plugin-global state or used by later invocations.
Verify Observation Behavior
Use the following procedure to verify all nine observation registrations without confusing observability changes with execution changes:
- Activate the example with
observe.enabled = true,redact_keys = ["secret"], and the remaining feature groups disabled. - Emit a mark and open and close a scope whose data, category profile, and metadata each
contain a
secretkey. Capture the subscriber output. - Execute a tool request and an LLM request and response containing the same key. Use a built-in codec for the model call and repeat once without a codec.
- Assert that every emitted observability field is redacted and tagged while the tool callback, model callback, and application result still contain their original real values.
- Clear the component and emit another mark. Confirm that neither sanitization nor the example subscriber runs.
Success means all nine observation registrations produce observable evidence, codec and fallback paths both redact safely, and no sanitizer accidentally changes execution.