Class RedactingLLMCallPublisher

java.lang.Object
com.tnsai.quality.redaction.RedactingLLMCallPublisher
All Implemented Interfaces:
com.tnsai.llm.observability.LLMCallPublisher

public final class RedactingLLMCallPublisher extends Object implements com.tnsai.llm.observability.LLMCallPublisher
LLMCallPublisher decorator that scrubs PII / secrets out of a captured LLMCallLog before delegating (TNS-417, follow-up to TNS-374).

Companion to RedactingAgentEventPublisher, which does the same job for TnsAIEvent. Lives in tnsai-quality for the same reason: the Redactor SPI is here, and tnsai-quality already depends on tnsai-llm (TNS-374). Putting the decorator next to the redaction SPI keeps the two pieces co-located and avoids a cycle-creating reverse dep from tnsai-llm into tnsai-quality.

What gets scrubbed

Every LLM-input and LLM-output surface that could leak user content:
  • systemPrompt — caller-derived, possibly templated with secrets.
  • messages — every Map entry walked recursively via Redactor.scrubValue(java.lang.Object, com.tnsai.quality.redaction.RedactionContext).
  • parameters — same.
  • content — model output text.
  • toolCalls — each call's arguments map (the model often echoes user input verbatim into tool args).
  • reasoningContent — reasoning-model thinking text.
  • error.message — providers sometimes echo prompt content back in error responses.
  • providerExtensions — opaque map; recursive scrub through the scrubValue default.
Pure metadata (call id, timestamps, provider/model strings, token counts, cost, finish reason, retry attempt, endpoint) passes through unchanged.

Scope hint

Prompt-side fields use RedactionScope.LLM_PROMPT; response- and error-side fields use RedactionScope.LLM_RESPONSE. Tenant-aware redactors that distinguish "scrub aggressively on outbound prompts" from "scrub the response" can hook on the scope.

Composition


 LLMCallPublisher otlp = ...;
 LLMCallPublisher chain = new SamplingLLMCallPublisher(
         new RedactingLLMCallPublisher(otlp, redactor),
         SamplingPolicies.production());
 
Wrap redaction inside sampling so calls that survive sampling are already PII-safe and the redactor only pays the cost of the events that actually ship downstream.

Thread-safety

Stateless beyond the immutable delegate + redactor. Redactor implementations are required by their SPI to be thread-safe.
Since:
0.10.1 (TNS-417)
  • Field Summary

    Fields inherited from interface com.tnsai.llm.observability.LLMCallPublisher

    NOOP
  • Constructor Summary

    Constructors
    Constructor
    Description
    RedactingLLMCallPublisher(com.tnsai.llm.observability.LLMCallPublisher delegate, Redactor redactor)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    publish(com.tnsai.llm.observability.LLMCallLog call)
     

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • RedactingLLMCallPublisher

      public RedactingLLMCallPublisher(com.tnsai.llm.observability.LLMCallPublisher delegate, Redactor redactor)
  • Method Details

    • publish

      public void publish(com.tnsai.llm.observability.LLMCallLog call)
      Specified by:
      publish in interface com.tnsai.llm.observability.LLMCallPublisher