feat(moa): add optional privacy redaction filter for reference outputs (#59959) - #60463
feat(moa): add optional privacy redaction filter for reference outputs (#59959)#60463webtecnica wants to merge 1 commit into
Conversation
(cherry picked from commit fd184b037d226f8107426d4289efbdc5c4386edc)
fd184b0 to
3428e70
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for adding an opt-in privacy control for MoA references. The current main path does expose raw reference output, so the feature premise is valid.
Problems
agent/moa_loop.py:1019redacts after the persistent MoA path has already stored raw tuples in_pending_trace(agent/moa_loop.py:1033-1038) and emitted raw text to the UI callback (agent/moa_loop.py:1047-1054).agent/moa_trace.py:143-145serializesacct.output, which remains raw. The filter therefore does not protect the display ormoa.save_tracespaths described in #59959.- The PR adds no regression tests, despite
tests/run_agent/test_moa_loop_mode.py:940-1015already exercising real trace persistence. agent/redact.py:70-305is the established secret scrubber and covers formats absent from the new local regex list. Reusing it avoids divergent secret coverage.
Suggested changes
- Apply redaction before caching, tracing, and
moa.referenceemission; preserve redacted values in the trace payload as well as aggregator guidance. - Reuse
redact_sensitive_text(..., force=True)for secrets and add focused email/phone handling around it. - Add enabled/disabled tests for display events, aggregator context, cache reuse, and a saved trace.
Automated hermes-sweeper review.
| @@ -957,6 +1018,13 @@ def create(self, **api_kwargs: Any) -> Any: | |||
| ref_count=_ref_count, | |||
| ) | |||
There was a problem hiding this comment.
This runs after the surrounding create() path has already populated _pending_trace and emitted every moa.reference callback. Consequently the UI and moa.save_traces still receive the original text (_RefAccounting.output is what save_moa_turn serializes). Redact immediately after the fan-out result is created, before cache/trace/callback handling, and make the trace payload use the redacted value.
Adds moa.privacy_filter ('' | display | full, default off — issue #59959):
- display: redact user-visible surfaces only (reference blocks emitted to
the UI + saved MoA trace records, including per-advisor full input/output
and the aggregator-input copy); the aggregator sees raw advisor text so
synthesis quality is unaffected.
- full: additionally redact the advisor text injected into the aggregator
prompt, on both the persistent facade path and the one-shot /moa
synthesis path (the issue's literal ask). Legacy boolean true maps here.
Secret/credential shapes (API-key prefixes, JWTs, private keys, DB
connection strings) are delegated to the central redactor
(agent.redact.redact_sensitive_text, force=True + code_file=True); the MoA
filter adds only email and clearly delimited phone-number patterns. No
bare 10-digit matching: line numbers, timestamps, epoch values, git SHAs,
IPs, versions, and source-code assignments in code-review-shaped advisory
text pass through byte-identical. The reference cache always holds raw
text — redaction happens at each consuming surface, so a mid-session mode
change never leaks or double-redacts.
Reworked from PR #60463: replaced its hand-rolled pattern list (which
matched bare digit runs and re-implemented key shapes) with central-
redactor reuse + safe patterns, and split the single boolean into
display/full modes. Credited for the feature framing.
Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
Adds moa.privacy_filter ('' | display | full, default off — issue #59959):
- display: redact user-visible surfaces only (reference blocks emitted to
the UI + saved MoA trace records, including per-advisor full input/output
and the aggregator-input copy); the aggregator sees raw advisor text so
synthesis quality is unaffected.
- full: additionally redact the advisor text injected into the aggregator
prompt, on both the persistent facade path and the one-shot /moa
synthesis path (the issue's literal ask). Legacy boolean true maps here.
Secret/credential shapes (API-key prefixes, JWTs, private keys, DB
connection strings) are delegated to the central redactor
(agent.redact.redact_sensitive_text, force=True + code_file=True); the MoA
filter adds only email and clearly delimited phone-number patterns. No
bare 10-digit matching: line numbers, timestamps, epoch values, git SHAs,
IPs, versions, and source-code assignments in code-review-shaped advisory
text pass through byte-identical. The reference cache always holds raw
text — redaction happens at each consuming surface, so a mid-session mode
change never leaks or double-redacts.
Reworked from PR #60463: replaced its hand-rolled pattern list (which
matched bare digit runs and re-implemented key shapes) with central-
redactor reuse + safe patterns, and split the single boolean into
display/full modes. Credited for the feature framing.
Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
|
Closing with credit — the privacy filter shipped via cluster PR #70284 (commit f7b90e6) as a redesigned implementation with you credited (Co-authored-by). Changes from your version: the repo's central redaction helpers are reused for secret/credential shapes, the bare 10-digit phone pattern was replaced with delimited-format matching (line numbers/timestamps/IDs in code advisories no longer get mangled), and the filter has display/full modes — full matches your issue #59959's literal ask of redacting the aggregator input. 12 filter tests included. Thanks for pushing on this! |
Adds moa.privacy_filter ('' | display | full, default off — issue NousResearch#59959):
- display: redact user-visible surfaces only (reference blocks emitted to
the UI + saved MoA trace records, including per-advisor full input/output
and the aggregator-input copy); the aggregator sees raw advisor text so
synthesis quality is unaffected.
- full: additionally redact the advisor text injected into the aggregator
prompt, on both the persistent facade path and the one-shot /moa
synthesis path (the issue's literal ask). Legacy boolean true maps here.
Secret/credential shapes (API-key prefixes, JWTs, private keys, DB
connection strings) are delegated to the central redactor
(agent.redact.redact_sensitive_text, force=True + code_file=True); the MoA
filter adds only email and clearly delimited phone-number patterns. No
bare 10-digit matching: line numbers, timestamps, epoch values, git SHAs,
IPs, versions, and source-code assignments in code-review-shaped advisory
text pass through byte-identical. The reference cache always holds raw
text — redaction happens at each consuming surface, so a mid-session mode
change never leaks or double-redacts.
Reworked from PR NousResearch#60463: replaced its hand-rolled pattern list (which
matched bare digit runs and re-implemented key shapes) with central-
redactor reuse + safe patterns, and split the single boolean into
display/full modes. Credited for the feature framing.
Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
Add optional privacy/redaction filter for MoA reference outputs. When
moa.privacy_filter: true, sensitive data (emails, phones, API keys) in reference outputs is redacted. Closes #59959