feat(tools): add governance hook for memory retrieval (#1348)#1363
Open
AyushKashyapII wants to merge 1 commit into
Open
feat(tools): add governance hook for memory retrieval (#1348)#1363AyushKashyapII wants to merge 1 commit into
AyushKashyapII wants to merge 1 commit into
Conversation
…1348) Signed-off-by: Ayush KAshyap <kashyap11ayush02@gmail.com>
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
Adds an optional governance hook at the memory-retrieval boundary — the point between Supermemory returning
profile()/search()results and those results reaching an agent's context. Closes the generic-hook option raised in #1348.Supermemory doesn't implement PII redaction, prompt-injection detection, or audit logging itself. Instead, this adds a pluggable extension point so any external governance provider (e.g. TealTiger, or an org's own compliance layer) can inspect, rewrite, drop, or block memories before they're formatted and injected into the LLM prompt — without hardcoding a dependency on any one vendor.
Why this approach (vs. the other options in #1348)
The issue proposed three paths: (a) a standalone package needing no core changes, (b) a generic hook API, (c) inline PII/injection detection built into core. This PR implements (b) — it's the only option that's actually a scoped, provider-agnostic change to this repo; (a) needs nothing here, and (c) would mean Supermemory building and maintaining its own redaction/detection logic, which duplicates what governance SDKs already do.
What changed
The hook is a plain function:
(profile, context) => profile | Promise<profile>, called with the raw retrieved memories (not yet deduplicated or formatted) plus{ containerTag, queryText, mode }. It's optional everywhere — omitting it changes nothing.Wired into every place memories get fetched and handed to an LLM:
packages/tools/src/shared/types.ts— newMemoryGovernanceContext/MemoryGovernanceHooktypes, added toSupermemoryBaseOptions.packages/tools/src/shared/memory-client.ts—buildMemoriesText()runs the hook right after the/v4/profilefetch, before dedup/formatting. This is the shared chokepoint used by most integrations.vercel/middleware.ts), Mastra (mastra/processor.ts,mastra/types.ts), VoltAgent (voltagent/middleware.ts) — threaded through tobuildMemoriesText. VoltAgent's separate "advanced search" path (which bypassesbuildMemoriesText) also runs the hook on its raw results.openai/middleware.ts) — has its own duplicated fetch/format logic (doesn't useshared/), so the hook is wired in independently for both the Chat Completions and Responses API paths.apps/mcp/src/client.ts) —SupermemoryClienttakes an optionalgovernance: { onSearch?, onProfile? }hook, applied at the end ofsearch()/getProfile(), right before results become MCP tool output.Not included (open questions for maintainers)
apps/mcp/src/server.ts'sgetClient()doesn't wire a hook in — there's no existing config mechanism to source one from at request time in the hosted Cloudflare Workers deployment, and inventing one (env var, webhook, etc.) felt like a separate architectural decision.Test plan
shared/memory-client.test.ts: stubs/v4/profileto return a memory containing a fake SSN, passes agovernanceHookthat redacts SSN-shaped strings, and asserts both (1) the hook receives the raw profile + correct context, and (2) the final formatted output contains[REDACTED]and never the real SSN.bun run testinpackages/tools— 90 passing, no regressions (2 pre-existing unrelated failures: one needs a liveSUPERMEMORY_API_KEY, one has a pre-existing broken import onmain).bun run check-types— no new errors introduced; confirmed viagit stashthat the one remaining error inopenai/middleware.tspre-dates this change, and this change incidentally fixes a pre-existing type error involtagent/middleware.ts