NanoBot AgentHook integration that redacts PII before LLM calls and restores original values in responses.
src/nanobot_hook/
├── __init__.py # Exports PrivacyFilterHook
└── hook.py # AgentHook implementation
# IMPORTANT: privacy-filter must be installed first (editable or from wheel)
cd ../privacy-filter
uv pip install -e .
# Then work on nanobot-hook
cd ../nanobot-hook
uv sync
# Build wheel
uv buildpyproject.tomldepends on"privacy-filter"(local package, not PyPI yet)- Optional extra:
nanobot→ installsnanobot-ai(the AgentHook framework) - Must install privacy-filter (editable:
uv pip install -e ../privacy-filter) before nanobot-hook will work
From nanobot.agent.hook:
class AgentHook:
def __init__(self, reraise: bool = False) -> None
async def before_iteration(self, context: AgentHookContext) -> None
async def after_iteration(self, context: AgentHookContext) -> None
def finalize_content(self, context: AgentHookContext, content: str | None) -> str | None
@dataclass
class AgentHookContext:
iteration: int
messages: list[dict[str, Any]] # Mutate in place for redaction
response: LLMResponse | None
final_content: str | None
...class PrivacyFilterHook(AgentHook):
def __init__(self, min_score=0.8, entity_types=None, cache_dir=None)
async def before_iteration(self, context: AgentHookContext) -> None # Redact PII
def finalize_content(self, context: AgentHookContext, content: str | None) -> str | None # Unredactbefore_iteration()— creates freshPiiStore, redacts all text content incontext.messagesfinalize_content()— restores original values from placeholders in the LLM response
- String content:
{"role": "user", "content": "My email is..."} - List content (OpenAI vision format):
{"type": "text", "text": "..."}— only redactstype: "text"parts - Only processes
role: "user"androle: "system"messages
from nanobot_hook import PrivacyFilterHook
hook = PrivacyFilterHook(min_score=0.9)
# Register with NanoBot agent's CompositeHookpyproject.toml uses:
[tool.hatch.build.targets.wheel]
packages = ["src/nanobot_hook"]This means the package imports as nanobot_hook (root level), not src.nanobot_hook. The src/ directory is a build artifact path, not a namespace package.
This is a separate package (nanobot-privacy-filter-hook) that depends on privacy-filter.
Important publishing order:
privacy-filtermust be on PyPI first- Wait a few minutes for PyPI index propagation
- Then build/publish
nanobot-privacy-filter-hook
# 1. Ensure privacy-filter is published to PyPI
cd ../privacy-filter
uv build
uv publish dist/*
# 2. Wait for PyPI, then build/publish nanobot-hook
cd ../nanobot-hook
uv build
uv publish dist/*Note: nanobot-hook fails to build if privacy-filter is not on PyPI (pyproject.toml declares it as a dependency).
privacy-filter— Core PII library (local dependency)nanobot-ai(optional) — NanoBot AgentHook framework
Verified against: https://github.com/HKUDS/nanobot/blob/main/nanobot/agent/hook.py
AgentHookContextis the proper context type (notAny)context.messagesislist[dict[str, Any]]— mutate in place for redactionfinalize_contentis a pipeline method (not async) — transforms content before sending to user- Hooks are registered via
CompositeHook([hook1, hook2, ...])