feat(redaction): add event-level redactEvent hook#49
Merged
Conversation
Add a redactEvent option to AgentCatOptions that receives the full Event object before publishing, complementing the existing string-level redactSensitiveInformation hook. Consumers can inspect event metadata (resourceName, eventType, parameters, response, etc.) to make context-aware redaction decisions, return a modified event, or return null to drop the event entirely. - New RedactEventFunction type, exported from the package root - Hook runs before string-level redaction, so it sees raw values; string redaction, sanitization, and truncation still run on its output - System-managed fields (id, sessionId, projectId, eventType, timestamp) are restored if the hook alters them - Hook errors drop the event and log, matching existing redaction semantics - Attached centrally in publishEvent, which also brings custom events published via publishCustomEvent on tracked servers under the hook
…tion The queue's process() previously handled the mechanics of applying the redactEvent hook result: clearing the event object, reassigning fields, and re-attaching the string-level redaction function. Consolidate all of that into applyEventRedaction, which already owns the rest of the hook contract (carrier-field stripping, system-managed field restoration). The helper now rewrites the event in place and returns whether the event was kept, so the queue reduces to a single call plus its existing drop/log handling. No behavior change.
kashishhora
approved these changes
Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Redaction decisions often need more context than a single string. The existing
redactSensitiveInformationhook is applied blindly to every string field in an event, so consumers can't tell which tool produced a value, what type of event is being published, or which field a string belongs to.This PR adds a new event-level redaction hook,
redactEvent, alongside the existing string-level hook. It receives the fullEventobject —resourceName,eventType,parameters,response,userIntent, and the rest — and returns a modified event, ornullto drop the event entirely.Behavior
(event: Event) => Event | null | Promise<Event | null>— sync or async, exported asRedactEventFunction.redactEventruns first and sees raw, unredacted values with full event context.redactSensitiveInformation(if configured), sanitization, and truncation all run on its output, so the string-level scrubber remains the last line of defense.null/undefineddrops the event. If the hook throws, the event is dropped and the error is logged to~/agentcat.log— the same fail-closed semantics as the existing string-level hook.id,sessionId,projectId,eventType, andtimestampare restored if the hook changes or removes them, protecting session and project attribution. Everything else is fully consumer-controlled.Behavior change worth noting
The hook is attached centrally in the publish pipeline, which means custom events published via
publishCustomEventon a tracked server now also pass throughredactEvent. Custom events previously bypassed redaction entirely; the string-level hook's behavior for them is unchanged. Custom events published with a bare session ID string (no tracked server) still bypass redaction, since no tracked configuration exists there.Test plan
applyEventRedactionhelper: sync/async hooks, null/undefined drops, deletion honoring, system-managed field restoration, internal function fields never exposed to or persisted from the hook, error propagation (src/tests/redaction.test.ts)track()options, drop-on-null, drop-on-throw, ordering relative to string redaction (src/tests/eventQueue.test.ts)publishCustomEventcoverage (src/tests/redaction.test.ts)pnpm run prepublishOnlydist): drove a real MCP client/server with both hooks configured and a local HTTP capture server in place of the AgentCat API; confirmed rewritten parameters, dropped events, string redaction composing after the event hook, and that a throwing hook drops only the affected event without disrupting the server