Skip to content

LCORE-1831: Implement Redaction Safety Capability in Pydantic AI#1915

Open
arin-deloatch wants to merge 7 commits into
lightspeed-core:mainfrom
arin-deloatch:feat/LCORE-1831
Open

LCORE-1831: Implement Redaction Safety Capability in Pydantic AI#1915
arin-deloatch wants to merge 7 commits into
lightspeed-core:mainfrom
arin-deloatch:feat/LCORE-1831

Conversation

@arin-deloatch

@arin-deloatch arin-deloatch commented Jun 11, 2026

Copy link
Copy Markdown

Description

Add a regex-based PII redaction capability for pydantic-ai agents. This introduces:

  • Core engine (core.py): redact_text() function and immutable RedactionResult model for
    sequential regex-based text substitution
  • Configuration (config.py): RedactionRule and RedactionConfig Pydantic models with
    compile-time pattern validation and per-rule/global case sensitivity controls
  • Capability (capability.py): PiiRedactionCapability integrating with pydantic-ai's
    AbstractCapability to redact user prompts before model requests and model response text before
    returning to the caller

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: Claude Code (Claude Opus 4.6)
  • Generated by: N/A

Related Tickets & Documents

  • Closes LCORE-1831

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • uv run make format — passes, no reformats
  • uv run make verify — all linters pass (black, pylint 10/10, pyright 0 errors, ruff, pydocstyle,
    mypy, lint-openapi)
  • uv run pytest tests/unit/pydantic_ai_lightspeed/capabilities/ -v — 51/51 tests pass
  • Coverage: 99% (2 uncovered lines in capability.py)

Summary by CodeRabbit

  • New Features
    • Added a configurable PII redaction capability that scans user prompts and model responses, applies ordered regex rules, and replaces matched text according to customizable replacements and case-sensitivity options.
  • Tests
    • Added comprehensive unit tests covering redaction configuration, core redaction behavior, and request/response lifecycle integration.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8c1143e5-f894-4e27-989f-51c55c0deafe

📥 Commits

Reviewing files that changed from the base of the PR and between d5a97ab and 271c1f2.

📒 Files selected for processing (11)
  • src/models/config.py
  • src/pydantic_ai_lightspeed/capabilities/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/capability.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/config.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/core.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_capability.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_config.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_core.py
 __________________________________________________________________________________________________________________________
< Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things. >
 --------------------------------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

Walkthrough

This pull request introduces a configurable PII redaction capability for Pydantic AI Lightspeed Core Stack. The implementation provides regex-based pattern matching and replacement logic, configuration models with compiled pattern caching, and integration with Pydantic AI's request/response lifecycle hooks.

Changes

PII Redaction Capability Implementation

Layer / File(s) Summary
Core redaction types and text processing
src/pydantic_ai_lightspeed/capabilities/redaction/core.py, tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_core.py
CompiledPatterns type alias and RedactionResult frozen model define the redaction output shape. redact_text applies compiled regex patterns sequentially to input, accumulating substitution counts and returning redaction metadata. Tests validate immutability, no-match passthrough, single/multiple pattern application, and case-sensitivity behavior.
Configuration models and pattern compilation
src/pydantic_ai_lightspeed/capabilities/redaction/config.py, tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_config.py
RedactionRule captures pattern, replacement, and optional case-sensitive override. RedactionConfig holds ordered rules, global case-sensitivity flag, and compiles patterns at model construction time via @model_validator, exposing compiled patterns through a defensive copy property. Tests cover rule construction, regex compilation, case-sensitivity handling, and property immutability.
PiiRedactionCapability and message traversal
src/pydantic_ai_lightspeed/capabilities/redaction/capability.py, tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_capability.py
Helpers (_redact_string_content, _redact_text_content, _redact_content_item/list, _redact_user_prompt_part, _redact_message_parts, _redact_model_request, _redact_messages, _redact_response) recursively traverse and redact message structures, preserving identity when no changes occur. PiiRedactionCapability class implements before_model_request (redacts user prompts) and after_model_request (redacts response text parts), wiring into Pydantic AI lifecycle. Tests validate redaction across content types and lifecycle hook behavior.
Public API and package structure
src/pydantic_ai_lightspeed/capabilities/__init__.py, src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py, tests/unit/pydantic_ai_lightspeed/capabilities/__init__.py, tests/unit/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
Module docstrings document package purpose. Redaction subpackage __all__ list exposes PiiRedactionCapability, RedactionConfig, RedactionRule, RedactionResult, and redact_text as public API.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • asimurka
  • tisnik
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main change: implementation of a redaction safety capability for Pydantic AI. It is concise, clear, and includes the ticket identifier.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable sequence diagrams in the walkthrough.

Disable the reviews.sequence_diagrams setting to disable sequence diagrams in the walkthrough.

@anik120 anik120 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is not part of the scope of this PR, but is src/pydantic_ai... leaking implementation detail again @jrobertboos?

@asimurka asimurka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM in overall



def _redact_message_parts(
parts: Sequence[Any], compiled_patterns: CompiledPatterns

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to avoid Any in the whole module where possible.


def _redact_string_content(
text: str, compiled_patterns: CompiledPatterns
) -> str | None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer using Optional in the whole module.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback; addressed in d5a97ab

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pydantic_ai_lightspeed/capabilities/redaction/capability.py`:
- Line 1: Add module-level logging support by importing get_logger from log.py
and creating a logger instance at the top of the file after the module docstring
using logger = get_logger(__name__). This logger should then be used throughout
the capability module to audit PII redaction events, such as logging at debug
level when redaction rules match specific patterns and at info level for
redaction statistics and summaries. This approach aligns with coding guidelines
and provides valuable audit trails for the security-sensitive PII redaction
functionality.
- Line 5: Update all type annotations in the module to use modern pipe syntax
instead of Optional. Replace Optional[Type] with Type | None for all return type
annotations in the functions including _redact_text_content,
_redact_content_list, _redact_message_parts, and _redact_model_request. After
updating all function return types throughout the module, remove Optional from
the import statement at the top of the file since it will no longer be needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7e09e4f4-9b9b-4dcf-a8b9-cf61a5e8e1e4

📥 Commits

Reviewing files that changed from the base of the PR and between f5586a7 and d5a97ab.

📒 Files selected for processing (10)
  • src/pydantic_ai_lightspeed/capabilities/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/capability.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/config.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/core.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_capability.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_config.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_core.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 3
🧰 Additional context used
📓 Path-based instructions (3)
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.py: Use pytest for all unit and integration tests; do not use unittest
Use pytest.mark.asyncio marker for async tests

Files:

  • tests/unit/pydantic_ai_lightspeed/capabilities/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_core.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_capability.py
  • tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_config.py
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Use absolute imports for internal modules: from authentication import get_auth_dependency
Llama Stack imports: Use from llama_stack_client import AsyncLlamaStackClient
Check constants.py for shared constants before defining new ones
All modules must start with descriptive docstrings explaining purpose
Use logger = get_logger(__name__) from log.py for module logging
All functions must have complete type annotations for parameters and return types, use modern syntax (str | int), and include descriptive docstrings
Use snake_case with descriptive, action-oriented names for functions (get_, validate_, check_)
Avoid in-place parameter modification anti-patterns; return new data structures instead of modifying function parameters
Use async def for I/O operations and external API calls
Use standard log levels with clear purposes: debug() for diagnostic info, info() for program execution, warning() for unexpected events, error() for serious problems
All classes must have descriptive docstrings explaining purpose and use PascalCase with standard suffixes: Configuration, Error/Exception, Resolver, Interface
Abstract classes must use ABC with @abstractmethod decorators
Follow Google Python docstring conventions with required sections: Parameters, Returns, Raises, and Attributes for classes

Files:

  • src/pydantic_ai_lightspeed/capabilities/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/core.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/config.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/capability.py
src/**/__init__.py

📄 CodeRabbit inference engine (AGENTS.md)

Package __init__.py files must contain brief package descriptions

Files:

  • src/pydantic_ai_lightspeed/capabilities/__init__.py
  • src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py
🔇 Additional comments (6)
src/pydantic_ai_lightspeed/capabilities/redaction/config.py (1)

14-107: LGTM!

tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_config.py (1)

1-157: LGTM!

src/pydantic_ai_lightspeed/capabilities/redaction/capability.py (2)

31-258: LGTM!


261-325: LGTM!

tests/unit/pydantic_ai_lightspeed/capabilities/redaction/test_capability.py (1)

1-316: LGTM!

src/pydantic_ai_lightspeed/capabilities/redaction/__init__.py (1)

1-21: LGTM!

Comment thread src/pydantic_ai_lightspeed/capabilities/redaction/capability.py
Comment thread src/pydantic_ai_lightspeed/capabilities/redaction/capability.py
@asimurka

Copy link
Copy Markdown
Contributor

/ok-to-test

@asimurka asimurka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally like this decomposition to capability, core and config modules.



@dataclass
class PiiRedactionCapability(AbstractCapability[Any]):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use None for type argument as this corresponds to current implementation of lightspeed agent (with no dependencies). Use None as type annotation where possible.

@tisnik

tisnik commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/ok-to-test

@@ -0,0 +1,107 @@
"""Configuration models for PII redaction rules."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO this config (or rather config classes/models) should be added into src/models/config.py. At least to avoid circular dependencies, to allow us to generate documentation etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, it was my initial understanding that we were to keep everything pydantic_ai related separate to avoid any sorts of conflicts with the core source code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I am more than happy to make the changes necessary! Just to be thorough, it is expected that RedactionRule,RedactionConfig and RedactionResult are being moved to src/models/config.py, correct?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. This will be later part of LCORE config so it will be technically implementation agnostic.

@jrobertboos jrobertboos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -0,0 +1,12 @@
"""Configuration models for PII redaction rules.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this module entirely

Comment thread src/models/config.py
return list(self._compiled_patterns)


class RedactionResult(BaseModel):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a configuration model so return it back to core.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants