Class RedactingMemoryStore

java.lang.Object
com.tnsai.quality.redaction.RedactingMemoryStore
All Implemented Interfaces:
com.tnsai.memory.MemoryStore

public final class RedactingMemoryStore extends Object implements com.tnsai.memory.MemoryStore
MemoryStore decorator that scrubs PII / secrets out of every write before delegating to the underlying store (issue #80, sink integration #1 of 6).

Why a decorator: keeps the MemoryStore SPI in tnsai-core unchanged (no breaking change to consumers that don't want redaction) while letting users opt in with one line:


 Redactor redactor = new PatternRedactor(RedactionPatterns.defaults());
 MemoryStore store = new RedactingMemoryStore(new InMemoryStore(), redactor);
 agent.setMemoryStore(store);
 

What gets scrubbed: every write path — addMessage(role, content), addMessage(Map) (recursively via Redactor.scrubValue(java.lang.Object, com.tnsai.quality.redaction.RedactionContext)), and MemoryStore.search(java.lang.String, int) queries. Reads (MemoryStore.getHistory(), MemoryStore.getRecentHistory(int)) pass through unchanged because content stored via this decorator is already redacted; double-scrubbing wastes cycles. Lifecycle methods (init, clear, prune) carry no content and pass straight through.

Search query handling: the query is scrubbed with the same MEMORY_WRITE scope as writes — a query containing PII would otherwise leak into whatever vector / keyword backend the store dispatches to.

Thread-safety: delegates to the underlying store; the decorator itself is stateless beyond holding the immutable delegate + redactor + context supplier.

Since:
0.9.0 (issue #80, sink integration phase)
  • Constructor Details

    • RedactingMemoryStore

      public RedactingMemoryStore(com.tnsai.memory.MemoryStore delegate, Redactor redactor)
      Wrap delegate with redaction using redactor, passing EventContext.empty() on every scrub call.

      Use the three-arg constructor when you have a per-call tenant / agent context the redactor needs to dispatch policy on.

    • RedactingMemoryStore

      public RedactingMemoryStore(com.tnsai.memory.MemoryStore delegate, Redactor redactor, Supplier<com.tnsai.observability.events.EventContext> contextSupplier)
      Wrap delegate with redaction using redactor and a contextSupplier that returns the EventContext to attach to each scrub call. The supplier is invoked once per write (not cached) so per-call tenant-id / capability info flows through correctly.
      Throws:
      NullPointerException - if any arg is null
  • Method Details

    • init

      public void init(String agentId)
      Specified by:
      init in interface com.tnsai.memory.MemoryStore
    • addMessage

      public void addMessage(String role, String content)
      Specified by:
      addMessage in interface com.tnsai.memory.MemoryStore
    • addMessage

      public void addMessage(Map<String,Object> message)
      Specified by:
      addMessage in interface com.tnsai.memory.MemoryStore
    • getHistory

      public List<Map<String,Object>> getHistory()
      Specified by:
      getHistory in interface com.tnsai.memory.MemoryStore
    • getRecentHistory

      public List<Map<String,Object>> getRecentHistory(int limit)
      Specified by:
      getRecentHistory in interface com.tnsai.memory.MemoryStore
    • clear

      public void clear()
      Specified by:
      clear in interface com.tnsai.memory.MemoryStore
    • prune

      public void prune(int maxTokens)
      Specified by:
      prune in interface com.tnsai.memory.MemoryStore
    • search

      public List<String> search(String query, int limit)
      Specified by:
      search in interface com.tnsai.memory.MemoryStore